<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0035)http://nocash.emubase.de/gbatek.htm -->
<HTML><HEAD><TITLE>Specifications</TITLE>
<META content="text/html; charset=iso-8859-1" http-equiv=Content-Type>
<META name=GENERATOR content="MSHTML 9.00.8112.16434"></HEAD>
<BODY aLink=#0033cc bgColor=#ffffff text=#000000 vLink=#0033cc link=#0033cc>
<CENTER><A name=gbatek></A><FONT size=+3>GBATEK</FONT><BR>Gameboy Advance / 
Nintendo DS - Technical Info - Extracted from no$gba version 2.5
<P></CENTER>
<TABLE width="100%">
  <TBODY>
  <TR>
    <TD vAlign=top width="30%">
      <TABLE width="100%">
        <TBODY>
        <TR bgColor=#cccccc>
          <TD><A name=gbareference></A><FONT size=+2>&nbsp;GBA 
          Reference</FONT></TD></TR></TBODY></TABLE><BR><B>Overview</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbatechnicaldata">GBA Technical 
      Data</A><BR><A href="http://nocash.emubase.de/gbatek.htm#gbamemorymap">GBA 
      Memory Map</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbaiomap">GBA I/O 
      Map</A><BR><BR><B>Hardware Programming</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbalcdvideocontroller">GBA LCD 
      Video Controller</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbasoundcontroller">GBA Sound 
      Controller</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbatimers">GBA Timers</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbadmatransfers">GBA DMA 
      Transfers</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbacommunicationports">GBA 
      Communication Ports</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbakeypadinput">GBA Keypad 
      Input</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbainterruptcontrol">GBA 
      Interrupt Control</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbasystemcontrol">GBA System 
      Control</A><BR><BR><B>Other</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#gbacartridges">GBA 
      Cartridges</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#biosfunctions">BIOS 
      Functions</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#unpredictablethings">Unpredictable 
      Things</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#externalconnectors">External 
      Connectors</A><BR></TD>
    <TD vAlign=top width="40%">
      <TABLE width="100%">
        <TBODY>
        <TR bgColor=#cccccc>
          <TD><A name=ndsreference></A><FONT size=+2>&nbsp;NDS 
          Reference</FONT></TD></TR></TBODY></TABLE><BR><B>Overview</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dstechnicaldata">DS Technical 
      Data</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsiomaps">DS I/O 
      Maps</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsmemorymaps">DS 
      Memory Maps</A><BR><BR><B>Hardware Programming</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrol">DS Memory 
      Control</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsvideo">DS 
      Video</A><BR><A href="http://nocash.emubase.de/gbatek.htm#ds3dvideo">DS 3D 
      Video</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dssound">DS 
      Sound</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dssystemandbuiltinperipherals">DS 
      System and Built-in Peripherals</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dscartridgesencryptionfirmware">DS 
      Cartridges, Encryption, Firmware</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dsxboo">DS Xboo</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dswirelesscommunications">DS 
      Wireless Communications</A><BR><BR><B>Other</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#dsbackwardscompatiblegbamode">DS 
      GBA-Mode</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#biosfunctions">BIOS 
      Functions</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpureference">CPU 
      Reference</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#externalconnectors">External 
      Connectors</A><BR></TD>
    <TD vAlign=top width="30%">
      <TABLE width="100%">
        <TBODY>
        <TR bgColor=#cccccc>
          <TD><A name=cpureference></A><FONT size=+2>&nbsp;CPU 
          Reference</FONT></TD></TR></TBODY></TABLE><BR><B>General 
      Information</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpuoverview">CPU 
      Overview</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpuregisterset">CPU Register 
      Set</A><BR><A href="http://nocash.emubase.de/gbatek.htm#cpuflags">CPU 
      Flags</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpuexceptions">CPU 
      Exceptions</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpumemoryalignments">CPU Memory 
      Alignments</A><BR><BR><B>The Instruction Sets</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#thumbinstructionset">THUMB 
      Instruction Set</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#arminstructionset">ARM 
      Instruction Set</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#pseudoinstructionsanddirectives">Pseudos 
      &amp; Directives</A><BR><BR><B>Further Information</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
      System Control CP15</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpuinstructioncycletimes">CPU 
      Clock Cycles</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpuversions">CPU 
      Versions</A><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#cpudatasheet">CPU Data 
      Sheet</A><BR><BR><B>About GBATEK</B><BR><A 
      href="http://nocash.emubase.de/gbatek.htm#aboutthisdocument">About this 
      Document</A><BR></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbatechnicaldata></A><FONT size=+2>&nbsp;GBA Technical 
      Data</FONT></TD></TR></TBODY></TABLE><BR><B>CPU Modes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ARM Mode     ARM7TDMI 32bit RISC CPU, 16.78MHz, 32bit opcodes (GBA)
  THUMB Mode   ARM7TDMI 32bit RISC CPU, 16.78MHz, 16bit opcodes (GBA)
  CGB Mode     Z80/8080-style 8bit CPU, 4.2MHz or 8.4MHz  (CGB compatibility)
  DMG Mode     Z80/8080-style 8bit CPU, 4.2MHz (monochrome gameboy compatib.)
</PRE></TD></TR></TBODY></TABLE><B>Internal Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  BIOS ROM     16 KBytes
  Work RAM     288 KBytes (32K in-chip + 256K on-board)
  VRAM         96 KBytes
  OAM          1 KByte (128 OBJs 3x16bit, 32 OBJ-Rotation/Scalings 4x16bit)
  Palette RAM  1 KByte (256 BG colors, 256 OBJ colors)
</PRE></TD></TR></TBODY></TABLE><B>Video</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Display      240x160 pixels (2.9 inch TFT color LCD display)
  BG layers    4 background layers
  BG types     Tile/map based, or Bitmap based
  BG colors    256 colors, or 16 colors/16 palettes, or 32768 colors
  OBJ colors   256 colors, or 16 colors/16 palettes
  OBJ size     12 types (in range 8x8 up to 64x64 dots)
  OBJs/Screen  max. 128 OBJs of any size (up to 64x64 dots each)
  OBJs/Line    max. 128 OBJs of 8x8 dots size (under best circumstances)
  Priorities   OBJ/OBJ: 0-127, OBJ/BG: 0-3, BG/BG: 0-3
  Effects      Rotation/Scaling, alpha blending, fade-in/out, mosaic, window
  Backlight    GBA SP only (optionally by light on/off toggle button)
</PRE></TD></TR></TBODY></TABLE><B>Sound</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Analogue     4 channel CGB compatible (3x square wave, 1x noise)
  Digital      2 DMA sound channels
  Output       Built-in speaker (mono), or headphones socket (stereo)
</PRE></TD></TR></TBODY></TABLE><B>Controls</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Gamepad      4 Direction Keys, 6 Buttons
</PRE></TD></TR></TBODY></TABLE><B>Communication Ports</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Serial Port  Various transfer modes, 4-Player Link, Single Game Pak play
</PRE></TD></TR></TBODY></TABLE><B>External Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GBA Game Pak max. 32MB ROM or flash ROM + max 64K SRAM
  CGB Game Pak max. 32KB ROM + 8KB SRAM (more memory requires banking)
</PRE></TD></TR></TBODY></TABLE><B>Case Dimensions</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Size (mm)    GBA: 145x81x25 - GBA SP: 82x82x24 (closed), 155x82x24 (stretch)
</PRE></TD></TR></TBODY></TABLE><B>Power Supply</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Battery GBA  GBA: 2x1.5V DC (AA), Life-time approx. 15 hours
  Battery SP   GBA SP: Built-in rechargeable Lithium ion battery, 3.7V 600mAh
  External     GBA: 3.3V DC 350mA - GBA SP: 5.2V DC 320mA
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> ----------------------------------------------------------------------------
        ____._____________...___.____               _______________________
   ____/    :  CARTRIDGE  SIO   :    \____         | _____________________ |
  | L       _____________________  LED  R |        ||                     ||
  |        |                     |        |        ||   2.9" TFT SCREEN   ||
  |  _||_  |   2.9" TFT SCREEN   |    (A) |        || 240x160pix  61x40mm ||
  | |_  _| | 240x160pix  61x40mm | (B)    |        ||   WITH BACKLIGHT    ||
  |   ||   |    NO BACKLIGHT     |  ::::  |        ||                     ||
  |        |                     | SPEAKR |        ||_____________________||
  | STRT() |_____________________|  ::::  |        |  GAME BOY ADVANCE SP  |
  | SLCT()     GAME BOY ADVANCE    VOLUME |        |_______________________|
  |____  OFF-ON  BATTERY 2xAA PHONES  _==_|        |_|________|________|_|_|
       \__.##.__________________,,___/             |L    EXT1     EXT2    R|
                                   .::'            |          (*)      LEDSo
                                .::'     (OPENED)  (VOL_||_           (A)  o
   GBA SP SIDE VIEW          .::'                  |  |_  _| ,,,,,(B)      |
   (CLOSED)               .::'        (STRETCHED)  |    ||   ;SPK;         |
  ...................... _ ......................  |         '''''      ON #
  :_____________________(_).....................:  |       SLCT STRT    OFF#
  |. . . . . . . .'.'.   _|                        | CART.  ()   ()        |
  |_CARTRIDGE_:_BATT._:_|_| &lt;-- EXT1/EXT2          |_:___________________:_|
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> ----------------------------------------------------------------------------
     _____________________________________
    |        _____________________        |
    |       |                     |       |
    |       |    3" TFT SCREEN    |       |
    |       | 256x192pix  61x46mm |       |
    |       |      BACKLIGHT      |       |
    | ::::: |                     | ::::: |
    | ::::: |_____________________| ::::: |
   _|        _          ______   _        |_
  |L|_______| |________|      |_| |_______|R|
  |_______   _____________________   _______|
  |  PWR  | |                     | |SEL STA|
  |   _   | |    3" TFT SCREEN    | |       |
  | _| |_ | | 256x192pix  61x46mm | |   X   |
  ||_   _|| |      BACKLIGHT      | | Y   A |
  |  |_|  | |    TOUCH SCREEN     | |   B   |
  |       | |_____________________| |       |
  |_______|             NintendoDS  |_______|
  |         MIC                LEDS         |
  |_________________________________________|
       VOL        SLOT2(GBA)     MIC/PHONES
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>     _____________________________________
    |        _____________________        |
    |       |                     |       |
    |       |    3" TFT SCREEN    |       |
    |  ...  | 256x192pix  61x46mm |  ...  |
    |  ...  |      BACKLIGHT      |  ...  |
    |       |       DS LITE       |       |
    |       |_____________________|       |
    |___  _ _ _ _ _ _ _ _ _ _ _ _ _ _ ____|
   L| _ |_____________MIC____________|LEDS|R
    |   _    _____________________        |
    | _| |_ |                     |   X   |
    ||_   _||    3" TFT SCREEN    | Y   A |PWR
    |  |_|  | 256x192pix  61x46mm |   B   |
    |       |      BACKLIGHT      |       |
    |       |    TOUCH SCREEN     |oSTART |
    |       |_____________________|oSELECT|
    |_____________________________________|
       VOL        SLOT2(GBA)     MIC/PHONES
</PRE></TD></TR></TBODY></TABLE><BR><BR>The separate CPU modes cannot be 
operated simultaneously. Switching is allowed between ARM and THUMB modes only 
(that are the two GBA modes).<BR>This manual does not describe CGB and DMG 
modes, both are completely different than GBA modes, and both cannot be accessed 
from inside of GBA modes anyways.<BR><BR><B>Gameboy Player</B><BR>An GBA Adapter 
for the Gamecube console; allowing to play GBA games on a television set.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbagameboyplayer">GBA Gameboy 
Player</A><BR><BR><B>GBA SP Notes</B><BR>Deluxe version of the original GBA. 
With backlight, new folded laptop-style case, and built-in rechargeable battery. 
Appears to be 100% compatible with GBA, there seems to be no way to detect SPs 
by software.<BR><BR><B>Nintendo DS (Dual Screen) Notes</B><BR>New handheld with 
two screens, backwards compatible with GBA games, it is NOT backwards compatible 
with older 8bit games (mono/color gameboys) though..<BR>Also, the DS has no link 
port, so that GBA games will thus work only in single player mode, link-port 
accessoires like printers cannot be used, and most unfortunately multiboot won't 
work (trying to press Select+Start at powerup will just lock up the 
DS).<BR><BR><B>iQue Notes</B><BR>iQue is a brand name used by Nintendo in China, 
iQue GBA and iQue DS are essentially same as Nintendo GBA and Nintendo 
DS.<BR>The iQue DS contains a larger firmware chip (the charset additionally 
contains about 6700 simplified chinese characters), the bootmenu still allows to 
select (only) six languages (japanese has been replaced by chinese). The iQue DS 
can play normal international NDS games, plus chinese dedicated games. The 
latter ones won't work on normal NDS consoles (that, reportedly simply due to a 
firmware-version check contained in chinese dedicated games, aside from that 
check, the games should be fully compatible with NDS consoles).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbamemorymap></A><FONT size=+2>&nbsp;GBA Memory 
  Map</FONT></TD></TR></TBODY></TABLE><BR><B>General Internal Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000-00003FFF   BIOS - System ROM         (16 KBytes)
  00004000-01FFFFFF   Not used
  02000000-0203FFFF   WRAM - On-board Work RAM  (256 KBytes) 2 Wait
  02040000-02FFFFFF   Not used
  03000000-03007FFF   WRAM - In-chip Work RAM   (32 KBytes)
  03008000-03FFFFFF   Not used
  04000000-040003FE   I/O Registers
  04000400-04FFFFFF   Not used
</PRE></TD></TR></TBODY></TABLE><B>Internal Display Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  05000000-050003FF   BG/OBJ Palette RAM        (1 Kbyte)
  05000400-05FFFFFF   Not used
  06000000-06017FFF   VRAM - Video RAM          (96 KBytes)
  06018000-06FFFFFF   Not used
  07000000-070003FF   OAM - OBJ Attributes      (1 Kbyte)
  07000400-07FFFFFF   Not used
</PRE></TD></TR></TBODY></TABLE><B>External Memory (Game Pak)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  08000000-09FFFFFF   Game Pak ROM/FlashROM (max 32MB) - Wait State 0
  0A000000-0BFFFFFF   Game Pak ROM/FlashROM (max 32MB) - Wait State 1
  0C000000-0DFFFFFF   Game Pak ROM/FlashROM (max 32MB) - Wait State 2
  0E000000-0E00FFFF   Game Pak SRAM    (max 64 KBytes) - 8bit Bus width
  0E010000-0FFFFFFF   Not used
</PRE></TD></TR></TBODY></TABLE><B>Unused Memory Area</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  10000000-FFFFFFFF   Not used (upper 4bits of address bus unused)
</PRE></TD></TR></TBODY></TABLE><BR><B>Default WRAM Usage</B><BR>By default, the 
256 bytes at 03007F00h-03007FFFh in Work RAM are reserved for Interrupt vector, 
Interrupt Stack, and BIOS Call Stack. The remaining WRAM is free for whatever 
use (including User Stack, which is initially located at 
03007F00h).<BR><BR><B>Address Bus Width and CPU Read/Write Access 
Widths</B><BR>Shows the Bus-Width, supported read and write widths, and the 
clock cycles for 8/16/32bit accesses.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Region        Bus   Read      Write     Cycles
  BIOS ROM      32    8/16/32   -         1/1/1
  Work RAM 32K  32    8/16/32   8/16/32   1/1/1
  I/O           32    8/16/32   8/16/32   1/1/1
  OAM           32    8/16/32   16/32     1/1/1 *
  Work RAM 256K 16    8/16/32   8/16/32   3/3/6 **
  Palette RAM   16    8/16/32   16/32     1/1/2 *
  VRAM          16    8/16/32   16/32     1/1/2 *
  GamePak ROM   16    8/16/32   -         5/5/8 **/***
  GamePak Flash 16    8/16/32   16/32     5/5/8 **/***
  GamePak SRAM  8     8         8         5     **
</PRE></TD></TR></TBODY></TABLE>Timing Notes:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  *   Plus 1 cycle if GBA accesses video memory at the same time.
  **  Default waitstate settings, see System Control chapter.
  *** Separate timings for sequential, and non-sequential accesses.
  One cycle equals approx. 59.59ns (ie. 16.78MHz clock).
</PRE></TD></TR></TBODY></TABLE>All memory (except GamePak SRAM) can be accessed 
by 16bit and 32bit DMA.<BR><BR><B>GamePak Memory</B><BR>Only DMA3 (and the CPU 
of course) may access GamePak ROM. GamePak SRAM can be accessed by the CPU only 
- restricted to bytewise 8bit transfers. The SRAM region is supposed for as 
external FLASH backup memory, or for battery-backed SRAM.<BR>For details about 
configuration of GamePak Waitstates, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasystemcontrol">GBA System 
Control</A><BR><BR><B>VRAM, OAM, and Palette RAM Access</B><BR>These memory 
regions can be accessed during H-Blank or V-Blank only (unless display is 
disabled by Forced Blank bit in DISPCNT register).<BR>There is an additional 
restriction for OAM memory: Accesses during H-Blank are allowed only if 'H-Blank 
Interval Free' in DISPCNT is set (which'd reduce number of display-able OBJs 
though).<BR>The CPU appears to be able to access VRAM/OAM/Palette at any time, a 
waitstate (one clock cycle) being inserted automatically in case that the 
display controller was accessing memory simultaneously. (Ie. unlike as in old 
8bit gameboy, the data will not get lost.)<BR><BR><B>CPU Mode 
Performance</B><BR>Note that the GamePak ROM bus is limited to 16bits, thus 
executing ARM instructions (32bit opcodes) from inside of GamePak ROM would 
result in a not so good performance. So, it'd be more recommended to use THUMB 
instruction (16bit opcodes) which'd allow each opcode to be read at 
once.<BR>(ARM instructions can be used at best performance by copying code from 
GamePak ROM into internal Work RAM)<BR><BR><B>Data Format</B><BR>Even though the 
ARM CPU itself would allow to select between Little-Endian and Big-Endian format 
by using an external circuit, in the GBA no such circuit exists, and the data 
format is always Little-Endian. That is, when accessing 16bit or 32bit data in 
memory, the least significant bits are stored in the first byte (smallest 
address), and the most significant bits in the last byte. (Ie. same as for 80x86 
and Z80 CPUs.)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbaiomap></A><FONT size=+2>&nbsp;GBA I/O 
  Map</FONT></TD></TR></TBODY></TABLE><BR><B>LCD I/O Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000000h  2    R/W  DISPCNT   LCD Control
  4000002h  2    R/W  -         Undocumented - Green Swap
  4000004h  2    R/W  DISPSTAT  General LCD Status (STAT,LYC)
  4000006h  2    R    VCOUNT    Vertical Counter (LY)
  4000008h  2    R/W  BG0CNT    BG0 Control
  400000Ah  2    R/W  BG1CNT    BG1 Control
  400000Ch  2    R/W  BG2CNT    BG2 Control
  400000Eh  2    R/W  BG3CNT    BG3 Control
  4000010h  2    W    BG0HOFS   BG0 X-Offset
  4000012h  2    W    BG0VOFS   BG0 Y-Offset
  4000014h  2    W    BG1HOFS   BG1 X-Offset
  4000016h  2    W    BG1VOFS   BG1 Y-Offset
  4000018h  2    W    BG2HOFS   BG2 X-Offset
  400001Ah  2    W    BG2VOFS   BG2 Y-Offset
  400001Ch  2    W    BG3HOFS   BG3 X-Offset
  400001Eh  2    W    BG3VOFS   BG3 Y-Offset
  4000020h  2    W    BG2PA     BG2 Rotation/Scaling Parameter A (dx)
  4000022h  2    W    BG2PB     BG2 Rotation/Scaling Parameter B (dmx)
  4000024h  2    W    BG2PC     BG2 Rotation/Scaling Parameter C (dy)
  4000026h  2    W    BG2PD     BG2 Rotation/Scaling Parameter D (dmy)
  4000028h  4    W    BG2X      BG2 Reference Point X-Coordinate
  400002Ch  4    W    BG2Y      BG2 Reference Point Y-Coordinate
  4000030h  2    W    BG3PA     BG3 Rotation/Scaling Parameter A (dx)
  4000032h  2    W    BG3PB     BG3 Rotation/Scaling Parameter B (dmx)
  4000034h  2    W    BG3PC     BG3 Rotation/Scaling Parameter C (dy)
  4000036h  2    W    BG3PD     BG3 Rotation/Scaling Parameter D (dmy)
  4000038h  4    W    BG3X      BG3 Reference Point X-Coordinate
  400003Ch  4    W    BG3Y      BG3 Reference Point Y-Coordinate
  4000040h  2    W    WIN0H     Window 0 Horizontal Dimensions
  4000042h  2    W    WIN1H     Window 1 Horizontal Dimensions
  4000044h  2    W    WIN0V     Window 0 Vertical Dimensions
  4000046h  2    W    WIN1V     Window 1 Vertical Dimensions
  4000048h  2    R/W  WININ     Inside of Window 0 and 1
  400004Ah  2    R/W  WINOUT    Inside of OBJ Window &amp; Outside of Windows
  400004Ch  2    W    MOSAIC    Mosaic Size
  400004Eh       -    -         Not used
  4000050h  2    R/W  BLDCNT    Color Special Effects Selection
  4000052h  2    W    BLDALPHA  Alpha Blending Coefficients
  4000054h  2    W    BLDY      Brightness (Fade-In/Out) Coefficient
  4000056h       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>Sound Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000060h  2  R/W  SOUND1CNT_L Channel 1 Sweep register       (NR10)
  4000062h  2  R/W  SOUND1CNT_H Channel 1 Duty/Length/Envelope (NR11, NR12)
  4000064h  2  R/W  SOUND1CNT_X Channel 1 Frequency/Control    (NR13, NR14)
  4000066h     -    -           Not used
  4000068h  2  R/W  SOUND2CNT_L Channel 2 Duty/Length/Envelope (NR21, NR22)
  400006Ah     -    -           Not used
  400006Ch  2  R/W  SOUND2CNT_H Channel 2 Frequency/Control    (NR23, NR24)
  400006Eh     -    -           Not used
  4000070h  2  R/W  SOUND3CNT_L Channel 3 Stop/Wave RAM select (NR30)
  4000072h  2  R/W  SOUND3CNT_H Channel 3 Length/Volume        (NR31, NR32)
  4000074h  2  R/W  SOUND3CNT_X Channel 3 Frequency/Control    (NR33, NR34)
  4000076h     -    -           Not used
  4000078h  2  R/W  SOUND4CNT_L Channel 4 Length/Envelope      (NR41, NR42)
  400007Ah     -    -           Not used
  400007Ch  2  R/W  SOUND4CNT_H Channel 4 Frequency/Control    (NR43, NR44)
  400007Eh     -    -           Not used
  4000080h  2  R/W  SOUNDCNT_L  Control Stereo/Volume/Enable   (NR50, NR51)
  4000082h  2  R/W  SOUNDCNT_H  Control Mixing/DMA Control
  4000084h  2  R/W  SOUNDCNT_X  Control Sound on/off           (NR52)
  4000086h     -    -           Not used
  4000088h  2  BIOS SOUNDBIAS   Sound PWM Control
  400008Ah  ..   -    -         Not used
  4000090h 2x10h R/W  WAVE_RAM  Channel 3 Wave Pattern RAM (2 banks!!)
  40000A0h  4    W    FIFO_A    Channel A FIFO, Data 0-3
  40000A4h  4    W    FIFO_B    Channel B FIFO, Data 0-3
  40000A8h       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>DMA Transfer Channels</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  40000B0h  4    W    DMA0SAD   DMA 0 Source Address
  40000B4h  4    W    DMA0DAD   DMA 0 Destination Address
  40000B8h  2    W    DMA0CNT_L DMA 0 Word Count
  40000BAh  2    R/W  DMA0CNT_H DMA 0 Control
  40000BCh  4    W    DMA1SAD   DMA 1 Source Address
  40000C0h  4    W    DMA1DAD   DMA 1 Destination Address
  40000C4h  2    W    DMA1CNT_L DMA 1 Word Count
  40000C6h  2    R/W  DMA1CNT_H DMA 1 Control
  40000C8h  4    W    DMA2SAD   DMA 2 Source Address
  40000CCh  4    W    DMA2DAD   DMA 2 Destination Address
  40000D0h  2    W    DMA2CNT_L DMA 2 Word Count
  40000D2h  2    R/W  DMA2CNT_H DMA 2 Control
  40000D4h  4    W    DMA3SAD   DMA 3 Source Address
  40000D8h  4    W    DMA3DAD   DMA 3 Destination Address
  40000DCh  2    W    DMA3CNT_L DMA 3 Word Count
  40000DEh  2    R/W  DMA3CNT_H DMA 3 Control
  40000E0h       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>Timer Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000100h  2    R/W  TM0CNT_L  Timer 0 Counter/Reload
  4000102h  2    R/W  TM0CNT_H  Timer 0 Control
  4000104h  2    R/W  TM1CNT_L  Timer 1 Counter/Reload
  4000106h  2    R/W  TM1CNT_H  Timer 1 Control
  4000108h  2    R/W  TM2CNT_L  Timer 2 Counter/Reload
  400010Ah  2    R/W  TM2CNT_H  Timer 2 Control
  400010Ch  2    R/W  TM3CNT_L  Timer 3 Counter/Reload
  400010Eh  2    R/W  TM3CNT_H  Timer 3 Control
  4000110h       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>Serial Communication (1)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000120h  4    R/W  SIODATA32 SIO Data (Normal-32bit Mode) (shared with below!)
  4000120h  2    R/W  SIOMULTI0 SIO Data 0 (Parent)    (Multi-Player Mode)
  4000122h  2    R/W  SIOMULTI1 SIO Data 1 (1st Child) (Multi-Player Mode)
  4000124h  2    R/W  SIOMULTI2 SIO Data 2 (2nd Child) (Multi-Player Mode)
  4000126h  2    R/W  SIOMULTI3 SIO Data 3 (3rd Child) (Multi-Player Mode)
  4000128h  2    R/W  SIOCNT    SIO Control Register
  400012Ah  2    R/W  SIOMLT_SEND SIO Data (Local of Multi-Player) (shared below)
  400012Ah  2    R/W  SIODATA8  SIO Data (Normal-8bit and UART Mode)
  400012Ch       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>Keypad Input</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000130h  2    R    KEYINPUT  Key Status
  4000132h  2    R/W  KEYCNT    Key Interrupt Control
</PRE></TD></TR></TBODY></TABLE><B>Serial Communication (2)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000134h  2    R/W  RCNT      SIO Mode Select/General Purpose Data
  4000136h  -    -    IR        Ancient - Infrared Register (Prototypes only)
  4000138h       -    -         Not used
  4000140h  2    R/W  JOYCNT    SIO JOY Bus Control
  4000142h       -    -         Not used
  4000150h  4    R/W  JOY_RECV  SIO JOY Bus Receive Data
  4000154h  4    R/W  JOY_TRANS SIO JOY Bus Transmit Data
  4000158h  2    R/?  JOYSTAT   SIO JOY Bus Receive Status
  400015Ah       -    -         Not used
</PRE></TD></TR></TBODY></TABLE><B>Interrupt, Waitstate, and Power-Down 
Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000200h  2    R/W  IE        Interrupt Enable Register
  4000202h  2    R/W  IF        Interrupt Request Flags / IRQ Acknowledge
  4000204h  2    R/W  WAITCNT   Game Pak Waitstate Control
  4000206h       -    -         Not used
  4000208h  2    R/W  IME       Interrupt Master Enable Register
  400020Ah       -    -         Not used
  4000300h  1    R/W  POSTFLG   Undocumented - Post Boot Flag
  4000301h  1    W    HALTCNT   Undocumented - Power Down Control
  4000302h       -    -         Not used
  4000410h  ?    ?    ?         Undocumented - Purpose Unknown / Bug ??? 0FFh
  4000411h       -    -         Not used
  4000800h  4    R/W  ?         Undocumented - Internal Memory Control (R/W)
  4000804h       -    -         Not used
  4xx0800h  4    R/W  ?         Mirrors of 4000800h (repeated each 64K)
</PRE></TD></TR></TBODY></TABLE><BR>All further addresses at 4XXXXXXh are unused 
and do not contain mirrors of the I/O area, with the only exception that 
4000800h is repeated each 64K (ie. mirrored at 4010800h, 4020800h, 
etc.)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbalcdvideocontroller></A><FONT size=+2>&nbsp;GBA LCD Video 
      Controller</FONT></TD></TR></TBODY></TABLE><BR><B>Registers</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiodisplaycontrol">LCD I/O Display 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiointerruptsandstatus">LCD I/O 
Interrupts and Status</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiobgcontrol">LCD I/O BG 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiobgscrolling">LCD I/O BG 
Scrolling</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiobgrotationscaling">LCD I/O BG 
Rotation/Scaling</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiowindowfeature">LCD I/O Window 
Feature</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiomosaicfunction">LCD I/O Mosaic 
Function</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdiocolorspecialeffects">LCD I/O 
Color Special Effects</A><BR><BR><B>VRAM</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdvramoverview">LCD VRAM 
Overview</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdvramcharacterdata">LCD VRAM 
Character Data</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdvrambgscreendataformatbgmap">LCD 
VRAM BG Screen Data Format (BG Map)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdvrambitmapbgmodes">LCD VRAM Bitmap 
BG Modes</A><BR><BR><B>Sprites</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdobjoverview">LCD OBJ - 
Overview</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdobjoamattributes">LCD OBJ - OAM 
Attributes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdobjoamrotationscalingparameters">LCD 
OBJ - OAM Rotation/Scaling Parameters</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdobjvramcharactertilemapping">LCD 
OBJ - VRAM Character (Tile) Mapping</A><BR><BR><B>Other</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcdcolorpalettes">LCD Color 
Palettes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#lcddimensionsandtimings">LCD 
Dimensions and Timings</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiodisplaycontrol></A><FONT size=+2>&nbsp;LCD I/O Display 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000000h - DISPCNT - LCD Control 
(Read/Write)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-2   BG Mode                (0-5=Video Mode 0-5, 6-7=Prohibited)
  3     Reserved / CGB Mode    (0=GBA, 1=CGB; can be set only by BIOS opcodes)
  4     Display Frame Select   (0-1=Frame 0-1) (for BG Modes 4,5 only)
  5     H-Blank Interval Free  (1=Allow access to OAM during H-Blank)
  6     OBJ Character VRAM Mapping (0=Two dimensional, 1=One dimensional)
  7     Forced Blank           (1=Allow FAST access to VRAM,Palette,OAM)
  8     Screen Display BG0  (0=Off, 1=On)
  9     Screen Display BG1  (0=Off, 1=On)
  10    Screen Display BG2  (0=Off, 1=On)
  11    Screen Display BG3  (0=Off, 1=On)
  12    Screen Display OBJ  (0=Off, 1=On)
  13    Window 0 Display Flag   (0=Off, 1=On)
  14    Window 1 Display Flag   (0=Off, 1=On)
  15    OBJ Window Display Flag (0=Off, 1=On)
</PRE></TD></TR></TBODY></TABLE><BR>The table summarizes the facilities of the 
separate BG modes (video modes).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Mode  Rot/Scal Layers Size               Tiles Colors       Features</B>
  0     No       0123   256x256..512x515   1024  16/16..256/1 SFMABP
  1     Mixed    012-   (BG0,BG1 as above Mode 0, BG2 as below Mode 2)
  2     Yes      --23   128x128..1024x1024 256   256/1        S-MABP
  3     Yes      --2-   240x160            1     32768        --MABP
  4     Yes      --2-   240x160            2     256/1        --MABP
  5     Yes      --2-   160x128            2     32768        --MABP
</PRE></TD></TR></TBODY></TABLE>Features: S)crolling, F)lip, M)osaic, 
A)lphaBlending, B)rightness, P)riority.<BR><BR>BG Modes 0-2 are Tile/Map-based. 
BG Modes 3-5 are Bitmap-based, in these modes 1 or 2 Frames (ie. bitmaps, or 
'full screen tiles') exists, if two frames exist, either one can be displayed, 
and the other one can be redrawn in background.<BR><BR><B>Blanking 
Bits</B><BR>Setting Forced Blank (Bit 7) causes the video controller to display 
white lines, and all VRAM, Palette RAM, and OAM may be accessed.<BR>"When the 
internal HV synchronous counter cancels a forced blank during a display period, 
the display begins from the beginning, following the display of two vertical 
lines." What ?<BR>Setting H-Blank Interval Free (Bit 5) allows to access OAM 
during H-Blank time - using this feature reduces the number of sprites that can 
be displayed per line.<BR><BR><B>Display Enable Bits</B><BR>By default, BG0-3 
and OBJ Display Flags (Bit 8-12) are used to enable/disable BGs and OBJ. When 
enabling Window 0 and/or 1 (Bit 13-14), color special effects may be used, and 
BG0-3 and OBJ are controlled by the window(s).<BR><BR><B>Frame 
Selection</B><BR>In BG Modes 4 and 5 (Bitmap modes), either one of the two 
bitmaps/frames may be displayed (Bit 4), allowing the user to update the other 
(invisible) frame in background. In BG Mode 3, only one frame exists.<BR>In BG 
Modes 0-2 (Tile/Map based modes), a similar effect may be gained by altering the 
base address(es) of BG Map and/or BG Character data.<BR><BR><B>4000002h - 
Undocumented - Green Swap (R/W)</B><BR>Normally, red green blue intensities for 
a group of two pixels is output as BGRbgr (uppercase for left pixel at even 
xloc, lowercase for right pixel at odd xloc). When the Green Swap bit is set, 
each pixel group is output as BgRbGr (ie. green intensity of each two pixels 
exchanged).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Green Swap  (0=Normal, 1=Swap)
  1-15  Not used
</PRE></TD></TR></TBODY></TABLE>This feature appears to be applied to the final 
picture (ie. after mixing the separate BG and OBJ layers). Eventually intended 
for other display types (with other pin-outs). With normal GBA hardware it is 
just producing an interesting dirt effect.<BR>The NDS DISPCNT registers are 
32bit (4000000h..4000003h), so Green Swap doesn't exist in NDS mode, however, 
the NDS does support Green Swap in GBA mode.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiointerruptsandstatus></A><FONT size=+2>&nbsp;LCD I/O 
      Interrupts and Status</FONT></TD></TR></TBODY></TABLE><BR><B>4000004h - DISPSTAT 
- General LCD Status (Read/Write)</B><BR>Display status and Interrupt control. 
The H-Blank conditions are generated once per scanline, including for the 
'hidden' scanlines during V-Blank.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     V-Blank flag   (Read only) (1=VBlank) (set in line 160..226; not 227)
  1     H-Blank flag   (Read only) (1=HBlank) (toggled in all lines, 0..227)
  2     V-Counter flag (Read only) (1=Match)  (set in selected line)
  3     V-Blank IRQ Enable         (1=Enable)
  4     H-Blank IRQ Enable         (1=Enable)
  5     V-Counter IRQ Enable       (1=Enable)
  6-7   Not used
  8-15  V-Count Setting (LYC)      (0..227)
</PRE></TD></TR></TBODY></TABLE>The V-Count-Setting value is much the same as 
LYC of older gameboys, when its value is identical to the content of the VCOUNT 
register then the V-Counter flag is set (Bit 2), and (if enabled in Bit 5) an 
interrupt is requested.<BR>Although the drawing time is only 960 cycles (240*4), 
the H-Blank flag is "0" for a total of 1006 cycles.<BR><BR><B>4000006h - VCOUNT 
- Vertical Counter (Read only)</B><BR>Indicates the currently drawn scanline, 
values in range from 160..227 indicate 'hidden' scanlines within VBlank 
area.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Current scanline (LY)      (0..227)
  8-15  Not Used
</PRE></TD></TR></TBODY></TABLE>Note: This is much the same than the 'LY' 
register of older gameboys.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiobgcontrol></A><FONT size=+2>&nbsp;LCD I/O BG 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000008h - BG0CNT - BG0 Control 
(R/W) (BG Modes 0,1 only)</B><BR><B>400000Ah - BG1CNT - BG1 Control (R/W) (BG 
Modes 0,1 only)</B><BR><B>400000Ch - BG2CNT - BG2 Control (R/W) (BG Modes 0,1,2 
only)</B><BR><B>400000Eh - BG3CNT - BG3 Control (R/W) (BG Modes 0,2 
only)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   BG Priority           (0-3, 0=Highest)
  2-3   Character Base Block  (0-3, in units of 16 KBytes) (=BG Tile Data)
  4-5   Not used (must be zero)
  6     Mosaic                (0=Disable, 1=Enable)
  7     Colors/Palettes       (0=16/16, 1=256/1)
  8-12  Screen Base Block     (0-31, in units of 2 KBytes) (=BG Map Data)
  13    Display Area Overflow (0=Transparent, 1=Wraparound; BG2CNT/BG3CNT only)
  14-15 Screen Size (0-3)
</PRE></TD></TR></TBODY></TABLE>Internal Screen Size (dots) and size of BG Map 
(bytes):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Value  Text Mode      Rotation/Scaling Mode
  0      256x256 (2K)   128x128   (256 bytes)
  1      512x256 (4K)   256x256   (1K)
  2      256x512 (4K)   512x512   (4K)
  3      512x512 (8K)   1024x1024 (16K)
</PRE></TD></TR></TBODY></TABLE>In case that some or all BGs are set to same 
priority then BG0 is having the highest, and BG3 the lowest priority.<BR><BR>In 
'Text Modes', the screen size is organized as follows: The screen consists of 
one or more 256x256 pixel (32x32 tiles) areas. When Size=0: only 1 area (SC0), 
when Size=1 or Size=2: two areas (SC0,SC1 either horizontally or vertically 
arranged next to each other), when Size=3: four areas (SC0,SC1 in upper row, 
SC2,SC3 in lower row). Whereas SC0 is defined by the normal BG Map base address 
(Bit 8-12 of BG#CNT), SC1 uses same address +2K, SC2 address +4K, SC3 address 
+6K. When the screen is scrolled it'll always wraparound.<BR><BR>In 
'Rotation/Scaling Modes', the screen size is organized as follows, only one area 
(SC0) of variable size 128x128..1024x1024 pixels (16x16..128x128 tiles) exists. 
When the screen is rotated/scaled (or scrolled?) so that the LCD viewport 
reaches outside of the background/screen area, then BG may be either displayed 
as transparent or wraparound (Bit 13 of BG#CNT).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiobgscrolling></A><FONT size=+2>&nbsp;LCD I/O BG 
      Scrolling</FONT></TD></TR></TBODY></TABLE><BR><B>4000010h - BG0HOFS - BG0 
X-Offset (W)</B><BR><B>4000012h - BG0VOFS - BG0 Y-Offset (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-8   Offset (0-511)
  9-15  Not used
</PRE></TD></TR></TBODY></TABLE>Specifies the coordinate of the upperleft first 
visible dot of BG0 background layer, ie. used to scroll the BG0 
area.<BR><BR><B>4000014h - BG1HOFS - BG1 X-Offset (W)</B><BR><B>4000016h - 
BG1VOFS - BG1 Y-Offset (W)</B><BR>Same as above BG0HOFS and BG0VOFS for BG1 
respectively.<BR><BR><B>4000018h - BG2HOFS - BG2 X-Offset (W)</B><BR><B>400001Ah 
- BG2VOFS - BG2 Y-Offset (W)</B><BR>Same as above BG0HOFS and BG0VOFS for BG2 
respectively.<BR><BR><B>400001Ch - BG3HOFS - BG3 X-Offset (W)</B><BR><B>400001Eh 
- BG3VOFS - BG3 Y-Offset (W)</B><BR>Same as above BG0HOFS and BG0VOFS for BG3 
respectively.<BR><BR>The above BG scrolling registers are exclusively used in 
Text modes, ie. for all layers in BG Mode 0, and for the first two layers in BG 
mode 1.<BR>In other BG modes (Rotation/Scaling and Bitmap modes) above registers 
are ignored. Instead, the screen may be scrolled by modifying the BG 
Rotation/Scaling Reference Point registers.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiobgrotationscaling></A><FONT size=+2>&nbsp;LCD I/O BG 
      Rotation/Scaling</FONT></TD></TR></TBODY></TABLE><BR><B>4000028h - BG2X_L - BG2 
Reference Point X-Coordinate, lower 16 bit (W)</B><BR><B>400002Ah - BG2X_H - BG2 
Reference Point X-Coordinate, upper 12 bit (W)</B><BR><B>400002Ch - BG2Y_L - BG2 
Reference Point Y-Coordinate, lower 16 bit (W)</B><BR><B>400002Eh - BG2Y_H - BG2 
Reference Point Y-Coordinate, upper 12 bit (W)</B><BR>These registers are 
replacing the BG scrolling registers which are used for Text mode, ie. the X/Y 
coordinates specify the source position from inside of the BG Map/Bitmap of the 
pixel to be displayed at upper left of the GBA display. The normal BG scrolling 
registers are ignored in Rotation/Scaling and Bitmap modes.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Fractional portion (8 bits)
  8-26  Integer portion    (19 bits)
  27    Sign               (1 bit)
  28-31 Not used
</PRE></TD></TR></TBODY></TABLE>Because values are shifted left by eight, 
fractional portions may be specified in steps of 1/256 pixels (this would be 
relevant only if the screen is actually rotated or scaled). Normal signed 32bit 
values may be written to above registers (the most significant bits will be 
ignored and the value will be cut-down to 28bits, but this is no actual problem 
because signed values have set all MSBs to the same value).<BR><BR><B>Internal 
Reference Point Registers</B><BR>The above reference points are automatically 
copied to internal registers during each vblank, specifying the origin for the 
first scanline. The internal registers are then incremented by dmx and dmy after 
each scanline.<BR>Caution: Writing to a reference point register by software 
outside of the Vblank period does immediately copy the new value to the 
corresponding internal register, that means: in the current frame, the new value 
specifies the origin of the &lt;current&gt; scanline (instead of the topmost 
scanline).<BR><BR><B>4000020h - BG2PA - BG2 Rotation/Scaling Parameter A (alias 
dx) (W)</B><BR><B>4000022h - BG2PB - BG2 Rotation/Scaling Parameter B (alias 
dmx) (W)</B><BR><B>4000024h - BG2PC - BG2 Rotation/Scaling Parameter C (alias 
dy) (W)</B><BR><B>4000026h - BG2PD - BG2 Rotation/Scaling Parameter D (alias 
dmy) (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Fractional portion (8 bits)
  8-14  Integer portion    (7 bits)
  15    Sign               (1 bit)
</PRE></TD></TR></TBODY></TABLE>See below for details.<BR><BR><B>400003Xh - 
BG3X_L/H, BG3Y_L/H, BG3PA-D - BG3 Rotation/Scaling Parameters</B><BR>Same as 
above BG2 Reference Point, and Rotation/Scaling Parameters, for BG3 
respectively.<BR><BR><B>dx (PA) and dy (PC)</B><BR>When transforming a 
horizontal line, dx and dy specify the resulting gradient and magnification for 
that line. For example:<BR>Horizontal line, length=100, dx=1, and dy=1. The 
resulting line would be drawn at 45 degrees, f(y)=1/1*x. Note that this would 
involve that line is magnified, the new length is SQR(100^2+100^2)=141.42. Yup, 
exactly - that's the old a^2 + b^2 = c^2 formula.<BR><BR><B>dmx (PB) and dmy 
(PD)</B><BR>These values define the resulting gradient and magnification for 
transformation of vertical lines. However, when rotating a square area (which is 
surrounded by horizontal and vertical lines), then the desired result should be 
usually a rotated &lt;square&gt; area (ie. not a parallelogram, for 
example).<BR>Thus, dmx and dmy must be defined in direct relationship to dx and 
dy, taking the example above, we'd have to set dmx=-1, and dmy=1, 
f(x)=-1/1*y.<BR><BR><B>Area Overflow</B><BR>In result of rotation/scaling it may 
often happen that areas outside of the actual BG area become moved into the LCD 
viewport. Depending of the Area Overflow bit (BG2CNT and BG3CNT, Bit 13) these 
areas may be either displayed (by wrapping the BG area), or may be displayed 
transparent.<BR>This works only in BG modes 1 and 2. The area overflow is 
ignored in Bitmap modes (BG modes 3-5), the outside of the Bitmaps is always 
transparent.<BR><BR>--- more details and confusing or helpful formulas 
---<BR><BR><B>The following parameters are required for Rotation/Scaling</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Rotation Center X and Y Coordinates (x0,y0)
  Rotation Angle                      (alpha)
  Magnification X and Y Values        (xMag,yMag)
</PRE></TD></TR></TBODY></TABLE>The display is rotated by 'alpha' degrees around 
the center.<BR>The displayed picture is magnified by 'xMag' along x-Axis (Y=y0) 
and 'yMag' along y-Axis (X=x0).<BR><BR><B>Calculating Rotation/Scaling 
Parameters A-D</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  A = Cos (alpha) / xMag    ;distance moved in direction x, same line
  B = Sin (alpha) / xMag    ;distance moved in direction x, next line
  C = Sin (alpha) / yMag    ;distance moved in direction y, same line
  D = Cos (alpha) / yMag    ;distance moved in direction y, next line
</PRE></TD></TR></TBODY></TABLE><BR><B>Calculating the position of a 
rotated/scaled dot</B><BR>Using the following expressions,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  x0,y0    Rotation Center
  x1,y1    Old Position of a pixel (before rotation/scaling)
  x2,y2    New position of above pixel (after rotation scaling)
  A,B,C,D  BG2PA-BG2PD Parameters (as calculated above)
</PRE></TD></TR></TBODY></TABLE>the following formula can be used to calculate 
x2,y2:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  x2 = A(x1-x0) + B(y1-y0) + x0
  y2 = C(x1-x0) + D(y1-y0) + y0
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiowindowfeature></A><FONT size=+2>&nbsp;LCD I/O Window 
      Feature</FONT></TD></TR></TBODY></TABLE><BR>The Window Feature may be used to 
split the screen into four regions. The BG0-3,OBJ layers and Color Special 
Effects can be separately enabled or disabled in each of these 
regions.<BR><BR><B>The DISPCNT Register</B><BR>DISPCNT Bits 13-15 are used to 
enable Window 0, Window 1, and/or OBJ Window regions, if any of these regions is 
enabled then the "Outside of Windows" region is automatically enabled, 
too.<BR>DISPCNT Bits 8-12 are kept used as master enable bits for the BG0-3,OBJ 
layers, a layer is displayed only if both DISPCNT and WININ/OUT enable bits are 
set.<BR><BR><B>4000040h - WIN0H - Window 0 Horizontal Dimensions 
(W)</B><BR><B>4000042h - WIN1H - Window 1 Horizontal Dimensions (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   X2, Rightmost coordinate of window, plus 1
  8-15  X1, Leftmost coordinate of window
</PRE></TD></TR></TBODY></TABLE>Garbage values of X2&gt;240 or X1&gt;X2 are 
interpreted as X2=240.<BR><BR><B>4000044h - WIN0V - Window 0 Vertical Dimensions 
(W)</B><BR><B>4000046h - WIN1V - Window 1 Vertical Dimensions (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Y2, Bottom-most coordinate of window, plus 1
  8-15  Y1, Top-most coordinate of window
</PRE></TD></TR></TBODY></TABLE>Garbage values of Y2&gt;160 or Y1&gt;Y2 are 
interpreted as Y2=160.<BR><BR><B>4000048h - WININ - Control of Inside of 
Window(s) (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Window 0 BG0-BG3 Enable Bits     (0=No Display, 1=Display)
  4     Window 0 OBJ Enable Bit          (0=No Display, 1=Display)
  5     Window 0 Color Special Effect    (0=Disable, 1=Enable)
  6-7   Not used
  8-11  Window 1 BG0-BG3 Enable Bits     (0=No Display, 1=Display)
  12    Window 1 OBJ Enable Bit          (0=No Display, 1=Display)
  13    Window 1 Color Special Effect    (0=Disable, 1=Enable)
  14-15 Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>400004Ah - WINOUT - Control of Outside of 
Windows &amp; Inside of OBJ Window (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Outside BG0-BG3 Enable Bits      (0=No Display, 1=Display)
  4     Outside OBJ Enable Bit           (0=No Display, 1=Display)
  5     Outside Color Special Effect     (0=Disable, 1=Enable)
  6-7   Not used
  8-11  OBJ Window BG0-BG3 Enable Bits   (0=No Display, 1=Display)
  12    OBJ Window OBJ Enable Bit        (0=No Display, 1=Display)
  13    OBJ Window Color Special Effect  (0=Disable, 1=Enable)
  14-15 Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>The OBJ Window</B><BR>The dimension of 
the OBJ Window is specified by OBJs which are having the "OBJ Mode" attribute 
being set to "OBJ Window". Any non-transparent dots of any such OBJs are marked 
as OBJ Window area. The OBJ itself is not displayed.<BR>The color, palette, and 
display priority of these OBJs are ignored. Both DISPCNT Bits 12 and 15 must be 
set when defining OBJ Window region(s).<BR><BR><B>Window Priority</B><BR>In case 
that more than one window is enabled, and that these windows do overlap, Window 
0 is having highest priority, Window 1 medium, and Obj Window lowest priority. 
Outside of Window is having zero priority, it is used for all dots which are not 
inside of any window region.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiomosaicfunction></A><FONT size=+2>&nbsp;LCD I/O Mosaic 
      Function</FONT></TD></TR></TBODY></TABLE><BR><B>400004Ch - MOSAIC - Mosaic Size 
(W)</B><BR>The Mosaic function can be separately enabled/disabled for BG0-BG3 by 
BG0CNT-BG3CNT Registers, as well as for each OBJ0-127 by OBJ attributes in OAM 
memory. Also, setting all of the bits below to zero effectively disables the 
mosaic function.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   BG Mosaic H-Size  (minus 1)
  4-7   BG Mosaic V-Size  (minus 1)
  8-11  OBJ Mosaic H-Size (minus 1)
  12-15 OBJ Mosaic V-Size (minus 1)
</PRE></TD></TR></TBODY></TABLE>Example: When setting H-Size to 5, then pixels 
0-5 of each display row are colorized as pixel 0, pixels 6-11 as pixel 6, pixels 
12-17 as pixel 12, and so on.<BR><BR>Normally, a 'mosaic-pixel' is colorized by 
the color of the upperleft covered pixel. In many cases it might be more 
desireful to use the color of the pixel in the center of the covered area - this 
effect may be gained by scrolling the background (or by adjusting the OBJ 
position, as far as upper/left rows/columns of OBJ are transparent).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdiocolorspecialeffects></A><FONT size=+2>&nbsp;LCD I/O Color 
      Special Effects</FONT></TD></TR></TBODY></TABLE><BR>Two types of Special Effects 
are supported: Alpha Blending (Semi-Transparency) allows to combine colors of 
two selected surfaces. Brightness Increase/Decrease adjust the brightness of the 
selected surface.<BR><BR><B>4000050h - BLDCNT - Color Special Effects Selection 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     BG0 1st Target Pixel (Background 0)
  1     BG1 1st Target Pixel (Background 1)
  2     BG2 1st Target Pixel (Background 2)
  3     BG3 1st Target Pixel (Background 3)
  4     OBJ 1st Target Pixel (Top-most OBJ pixel)
  5     BD  1st Target Pixel (Backdrop)
  6-7   Color Special Effect (0-3, see below)
         0 = None                (Special effects disabled)
         1 = Alpha Blending      (1st+2nd Target mixed)
         2 = Brightness Increase (1st Target becomes whiter)
         3 = Brightness Decrease (1st Target becomes blacker)
  8     BG0 2nd Target Pixel (Background 0)
  9     BG1 2nd Target Pixel (Background 1)
  10    BG2 2nd Target Pixel (Background 2)
  11    BG3 2nd Target Pixel (Background 3)
  12    OBJ 2nd Target Pixel (Top-most OBJ pixel)
  13    BD  2nd Target Pixel (Backdrop)
  14-15 Not used
</PRE></TD></TR></TBODY></TABLE>Selects the 1st Target layer(s) for special 
effects. For Alpha Blending/Semi-Transparency, it does also select the 2nd 
Target layer(s), which should have next lower display priority as the 1st 
Target.<BR>However, any combinations are possible, including that all layers may 
be selected as both 1st+2nd target, in that case the top-most pixel will be used 
as 1st target, and the next lower pixel as 2nd target.<BR><BR><B>4000052h - 
BLDALPHA - Alpha Blending Coefficients (W)</B><BR>Used for Color Special Effects 
Mode 1, and for Semi-Transparent OBJs.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-4   EVA Coefficient (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)
  5-7   Not used
  8-12  EVB Coefficient (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)
  13-15 Not used
</PRE></TD></TR></TBODY></TABLE>For this effect, the top-most non-transparent 
pixel must be selected as 1st Target, and the next-lower non-transparent pixel 
must be selected as 2nd Target, if so - and only if so, then color intensities 
of 1st and 2nd Target are mixed together by using the parameters in BLDALPHA 
register, for each pixel each R, G, B intensities are calculated separately:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  I = MIN ( 31, I1st*EVA + I2nd*EVB )
</PRE></TD></TR></TBODY></TABLE>Otherwise - for example, if only one target 
exists, or if a non-transparent non-2nd-target pixel is moved between the two 
targets, or if 2nd target has higher display priority than 1st target - then 
only the top-most pixel is displayed (at normal intensity, regardless of 
BLDALPHA).<BR><BR><B>4000054h - BLDY - Brightness (Fade-In/Out) Coefficient 
(W)</B><BR>Used for Color Special Effects Modes 2 and 3.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-4   EVY Coefficient (Brightness) (0..16 = 0/16..16/16, 17..31=16/16)
  5-15  Not used
</PRE></TD></TR></TBODY></TABLE>For each pixel each R, G, B intensities are 
calculated separately:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  I = I1st + (31-I1st)*EVY   ;For Brightness Increase
  I = I1st - (I1st)*EVY      ;For Brightness Decrease
</PRE></TD></TR></TBODY></TABLE>The color intensities of any selected 1st target 
surface(s) are increased or decreased by using the parameter in BLDY 
register.<BR><BR><B>Semi-Transparent OBJs</B><BR>OBJs that are defined as 
'Semi-Transparent' in OAM memory are always selected as 1st Target (regardless 
of BLDCNT Bit 4), and are always using Alpha Blending mode (regardless of BLDCNT 
Bit 6-7).<BR>The BLDCNT register may be used to perform Brightness effects on 
the OBJ (and/or other BG/BD layers). However, if a semi-transparent OBJ pixel 
does overlap a 2nd target pixel, then semi-transparency becomes priority, and 
the brightness effect will not take place (neither on 1st, nor 2nd 
target).<BR><BR><B>The OBJ Layer</B><BR>Before special effects are applied, the 
display controller computes the OBJ priority ordering, and isolates the top-most 
OBJ pixel. In result, only the top-most OBJ pixel is recursed at the time when 
processing special effects. Ie. alpha blending and semi-transparency can be used 
for OBJ-to-BG or BG-to-OBJ , but not for OBJ-to-OBJ.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdvramoverview></A><FONT size=+2>&nbsp;LCD VRAM 
      Overview</FONT></TD></TR></TBODY></TABLE><BR>The GBA contains 96 Kbytes VRAM 
built-in, located at address 06000000-06017FFF, depending on the BG Mode used as 
follows:<BR><BR><B>BG Mode 0,1,2 (Tile/Map based Modes)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06000000-0600FFFF  64 KBytes shared for BG Map and Tiles
  06010000-06017FFF  32 KBytes OBJ Tiles
</PRE></TD></TR></TBODY></TABLE>The shared 64K area can be split into BG Map 
area(s), and BG Tiles area(s), the respective addresses for Map and Tile areas 
are set up by BG0CNT-BG3CNT registers. The Map address may be specified in units 
of 2K (steps of 800h), the Tile address in units of 16K (steps of 
4000h).<BR><BR><B>BG Mode 0,1 (Tile/Map based Text mode)</B><BR>The tiles may 
have 4bit or 8bit color depth, minimum map size is 32x32 tiles, maximum is 64x64 
tiles, up to 1024 tiles can be used per map.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Item        Depth     Required Memory
  One Tile    4bit      20h bytes
  One Tile    8bit      40h bytes
  1024 Tiles  4bit      8000h (32K)
  1024 Tiles  8bit      10000h (64K) - excluding some bytes for BG map
  BG Map      32x32     800h (2K)
  BG Map      64x64     2000h (8K)
</PRE></TD></TR></TBODY></TABLE><BR><B>BG Mode 1,2 (Tile/Map based 
Rotation/Scaling mode)</B><BR>The tiles may have 8bit color depth only, minimum 
map size is 16x16 tiles, maximum is 128x128 tiles, up to 256 tiles can be used 
per map.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Item        Depth     Required Memory
  One Tile    8bit      40h bytes
  256  Tiles  8bit      4000h (16K)
  BG Map      16x16     100h bytes
  BG Map      128x128   4000h (16K)
</PRE></TD></TR></TBODY></TABLE><BR><B>BG Mode 3 (Bitmap based Mode for still 
images)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06000000-06013FFF  80 KBytes Frame 0 buffer (only 75K actually used)
  06014000-06017FFF  16 KBytes OBJ Tiles
</PRE></TD></TR></TBODY></TABLE><BR><B>BG Mode 4,5 (Bitmap based Modes)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06000000-06009FFF  40 KBytes Frame 0 buffer (only 37.5K used in Mode 4)
  0600A000-06013FFF  40 KBytes Frame 1 buffer (only 37.5K used in Mode 4)
  06014000-06017FFF  16 KBytes OBJ Tiles
</PRE></TD></TR></TBODY></TABLE><BR><B>Note</B><BR>Additionally to the above 
VRAM, the GBA also contains 1 KByte Palette RAM (at 05000000h) and 1 KByte OAM 
(at 07000000h) which are both used by the display controller as 
well.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdvramcharacterdata></A><FONT size=+2>&nbsp;LCD VRAM 
      Character Data</FONT></TD></TR></TBODY></TABLE><BR>Each character (tile) 
consists of 8x8 dots (64 dots in total). The color depth may be either 4bit or 
8bit (see BG0CNT-BG3CNT).<BR><BR><B>4bit depth (16 colors, 16 
palettes)</B><BR>Each tile occupies 32 bytes of memory, the first 4 bytes for 
the topmost row of the tile, and so on. Each byte representing two dots, the 
lower 4 bits define the color for the left (!) dot, the upper 4 bits the color 
for the right dot.<BR><BR><B>8bit depth (256 colors, 1 palette)</B><BR>Each tile 
occupies 64 bytes of memory, the first 8 bytes for the topmost row of the tile, 
and so on. Each byte selects the palette entry for each dot.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdvrambgscreendataformatbgmap></A><FONT size=+2>&nbsp;LCD 
      VRAM BG Screen Data Format (BG Map)</FONT></TD></TR></TBODY></TABLE><BR>The 
display background consists of 8x8 dot tiles, the arrangement of these tiles is 
specified by the BG Screen Data (BG Map). The separate entries in this map are 
as follows:<BR><BR><B>Text BG Screen (2 bytes per entry)</B><BR>Specifies the 
tile number and attributes. Note that BG tile numbers are always specified in 
steps of 1 (unlike OBJ tile numbers which are using steps of two in 256 color/1 
palette mode).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-9   Tile Number     (0-1023) (a bit less in 256 color mode, because
                           there'd be otherwise no room for the bg map)
  10    Horizontal Flip (0=Normal, 1=Mirrored)
  11    Vertical Flip   (0=Normal, 1=Mirrored)
  12-15 Palette Number  (0-15)    (Not used in 256 color/1 palette mode)
</PRE></TD></TR></TBODY></TABLE>A Text BG Map always consists of 32x32 entries 
(256x256 pixels), 400h entries = 800h bytes. However, depending on the BG Size, 
one, two, or four of these Maps may be used together, allowing to create 
backgrounds of 256x256, 512x256, 256x512, or 512x512 pixels, if so, the first 
map (SC0) is located at base+0, the next map (SC1) at base+800h, and so 
on.<BR><BR><B>Rotation/Scaling BG Screen (1 byte per entry)</B><BR>In this mode, 
only 256 tiles can be used. There are no x/y-flip attributes, the color depth is 
always 256 colors/1 palette.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Tile Number     (0-255)
</PRE></TD></TR></TBODY></TABLE>The dimensions of Rotation/Scaling BG Maps 
depend on the BG size. For size 0-3 that are: 16x16 tiles (128x128 pixels), 
32x32 tiles (256x256 pixels), 64x64 tiles (512x512 pixels), or 128x128 tiles 
(1024x1024 pixels).<BR><BR>The size and VRAM base address of the separate BG 
maps for BG0-3 are set up by BG0CNT-BG3CNT registers.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdvrambitmapbgmodes></A><FONT size=+2>&nbsp;LCD VRAM Bitmap 
      BG Modes</FONT></TD></TR></TBODY></TABLE><BR>In BG Modes 3-5 the background is 
defined in form of a bitmap (unlike as for Tile/Map based BG modes). Bitmaps are 
implemented as BG2, with Rotation/Scaling support. As bitmap modes are occupying 
80KBytes of BG memory, only 16KBytes of VRAM can be used for OBJ 
tiles.<BR><BR><B>BG Mode 3 - 240x160 pixels, 32768 colors</B><BR>Two bytes are 
associated to each pixel, directly defining one of the 32768 colors (without 
using palette data, and thus not supporting a 'transparent' BG color).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-4   Red Intensity   (0-31)
  5-9   Green Intensity (0-31)
  10-14 Blue Intensity  (0-31)
  15    Not used
</PRE></TD></TR></TBODY></TABLE>The first 480 bytes define the topmost line, the 
next 480 the next line, and so on. The background occupies 75 KBytes 
(06000000-06012BFF), most of the 80 Kbytes BG area, not allowing to redraw an 
invisible second frame in background, so this mode is mostly recommended for 
still images only.<BR><BR><B>BG Mode 4 - 240x160 pixels, 256 colors (out of 
32768 colors)</B><BR>One byte is associated to each pixel, selecting one of the 
256 palette entries. Color 0 (backdrop) is transparent, and OBJs may be 
displayed behind the bitmap.<BR>The first 240 bytes define the topmost line, the 
next 240 the next line, and so on. The background occupies 37.5 KBytes, allowing 
two frames to be used (06000000-060095FF for Frame 0, and 0600A000-060135FF for 
Frame 1).<BR><BR><B>BG Mode 5 - 160x128 pixels, 32768 colors</B><BR>Colors are 
defined as for Mode 3 (see above), but horizontal and vertical size are cut down 
to 160x128 pixels only - smaller than the physical dimensions of the LCD 
screen.<BR>The background occupies exactly 40 KBytes, so that BG VRAM may be 
split into two frames (06000000-06009FFF for Frame 0, and 0600A000-06013FFF for 
Frame 1).<BR><BR>In BG modes 4,5, one Frame may be displayed (selected by 
DISPCNT Bit 4), the other Frame is invisible and may be redrawn in 
background.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdobjoverview></A><FONT size=+2>&nbsp;LCD OBJ - 
      Overview</FONT></TD></TR></TBODY></TABLE><BR><B>General</B><BR>Objects (OBJs) 
are moveable sprites. Up to 128 OBJs (of any size, up to 64x64 dots each) can be 
displayed per screen, and under best circumstances up to 128 OBJs (of small 8x8 
dots size) can be displayed per horizontal display line.<BR><BR><B>Maximum 
Number of Sprites per Line</B><BR>The total available OBJ rendering cycles per 
line are<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1210  (=304*4-6)   If "H-Blank Interval Free" bit in DISPCNT register is 0
  954   (=240*4-6)   If "H-Blank Interval Free" bit in DISPCNT register is 1
</PRE></TD></TR></TBODY></TABLE>The required rendering cycles are (depending on 
horizontal OBJ size)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Cycles per &lt;n&gt; Pixels    OBJ Type              OBJ Type Screen Pixel Range
  n*1 cycles               Normal OBJs           8..64 pixels
  10+n*2 cycles            Rotation/Scaling OBJs 8..64 pixels   (area clipped)
  10+n*2 cycles            Rotation/Scaling OBJs 16..128 pixels (double size)
</PRE></TD></TR></TBODY></TABLE>Caution:<BR>The maximum number of OBJs per line 
is also affected by undisplayed (offscreen) OBJs which are having higher 
priority than displayed OBJs.<BR>To avoid this, move displayed OBJs to the begin 
of OAM memory (ie. OBJ0 has highest priority, OBJ127 lowest).<BR>Otherwise (in 
case that the program logic expects OBJs at fixed positions in OAM) at least 
take care to set the OBJ size of undisplayed OBJs to 8x8 with Rotation/Scaling 
disabled (this reduces the overload).<BR>Does the above also apply for 
VERTICALLY OFFSCREEN (or VERTICALLY not on CURRENT LINE) sprites 
?<BR><BR><B>VRAM - Character Data</B><BR>OBJs are always combined of one or more 
8x8 pixel Tiles (much like BG Tiles in BG Modes 0-2). However, OBJ Tiles are 
stored in a separate area in VRAM: 06010000-06017FFF (32 KBytes) in BG Mode 0-2, 
or 06014000-06017FFF (16 KBytes) in BG Mode 3-5.<BR>Depending on the size of the 
above area (16K or 32K), and on the OBJ color depth (4bit or 8bit), 256-1024 8x8 
dots OBJ Tiles can be defined.<BR><BR><B>OAM - Object Attribute 
Memory</B><BR>This memory area contains Attributes which specify position, size, 
color depth, etc. appearance for each of the 128 OBJs. Additionally, it contains 
32 OBJ Rotation/Scaling Parameter groups. OAM is located at 07000000-070003FF 
(sized 1 KByte).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdobjoamattributes></A><FONT size=+2>&nbsp;LCD OBJ - OAM 
      Attributes</FONT></TD></TR></TBODY></TABLE><BR><B>OBJ Attributes</B><BR>There 
are 128 entries in OAM for each OBJ0-OBJ127. Each entry consists of 6 bytes 
(three 16bit Attributes). Attributes for OBJ0 are located at 07000000, for OBJ1 
at 07000008, OBJ2 at 07000010, and so on.<BR><BR>As you can see, there are blank 
spaces at 07000006, 0700000E, 07000016, etc. - these 16bit values are used for 
OBJ Rotation/Scaling (as described in the next chapter) - they are not directly 
related to the separate OBJs.<BR><BR><B>OBJ Attribute 0 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-7   Y-Coordinate           (0-255)
  8     Rotation/Scaling Flag  (0=Off, 1=On)
  When Rotation/Scaling used (Attribute 0, bit 8 set):
    9     Double-Size Flag     (0=Normal, 1=Double)
  When Rotation/Scaling not used (Attribute 0, bit 8 cleared):
    9     OBJ Disable          (0=Normal, 1=Not displayed)
  10-11 OBJ Mode  (0=Normal, 1=Semi-Transparent, 2=OBJ Window, 3=Prohibited)
  12    OBJ Mosaic             (0=Off, 1=On)
  13    Colors/Palettes        (0=16/16, 1=256/1)
  14-15 OBJ Shape              (0=Square,1=Horizontal,2=Vertical,3=Prohibited)
</PRE></TD></TR></TBODY></TABLE>Caution: A very large OBJ (of 128 pixels 
vertically, ie. a 64 pixels OBJ in a Double Size area) located at Y&gt;128 will 
be treated as at Y&gt;-128, the OBJ is then displayed parts offscreen at the TOP 
of the display, it is then NOT displayed at the bottom.<BR><BR><B>OBJ Attribute 
1 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-8   X-Coordinate           (0-511)
  When Rotation/Scaling used (Attribute 0, bit 8 set):
    9-13  Rotation/Scaling Parameter Selection (0-31)
          (Selects one of the 32 Rotation/Scaling Parameters that
          can be defined in OAM, for details read next chapter.)
  When Rotation/Scaling not used (Attribute 0, bit 8 cleared):
    9-11  Not used
    12    Horizontal Flip      (0=Normal, 1=Mirrored)
    13    Vertical Flip        (0=Normal, 1=Mirrored)
  14-15 OBJ Size               (0..3, depends on OBJ Shape, see Attr 0)
          Size  Square   Horizontal  Vertical
          0     8x8      16x8        8x16
          1     16x16    32x8        8x32
          2     32x32    32x16       16x32
          3     64x64    64x32       32x64
</PRE></TD></TR></TBODY></TABLE><BR><B>OBJ Attribute 2 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-9   Character Name          (0-1023=Tile Number)
  10-11 Priority relative to BG (0-3; 0=Highest)
  12-15 Palette Number   (0-15) (Not used in 256 color/1 palette mode)
</PRE></TD></TR></TBODY></TABLE><BR><B>Notes:</B><BR><BR><B>OBJ Mode</B><BR>The 
OBJ Mode may be Normal, Semi-Transparent, or OBJ Window.<BR>Semi-Transparent 
means that the OBJ is used as 'Alpha Blending 1st Target' (regardless of BLDCNT 
register, for details see chapter about Color Special Effects).<BR>OBJ Window 
means that the OBJ is not displayed, instead, dots with non-zero color are used 
as mask for the OBJ Window, see DISPCNT and WINOUT for details.<BR><BR><B>OBJ 
Tile Number</B><BR>There are two situations which may divide the amount of 
available tiles by two (by four if both situations apply):<BR><BR>1. When using 
the 256 Colors/1 Palette mode, only each second tile may be used, the lower bit 
of the tile number should be zero (in 2-dimensional mapping mode, the bit is 
completely ignored).<BR><BR>2. When using BG Mode 3-5 (Bitmap Modes), only tile 
numbers 512-1023 may be used. That is because lower 16K of OBJ memory are used 
for BG. Attempts to use tiles 0-511 are ignored (not 
displayed).<BR><BR><B>Priority</B><BR>In case that the 'Priority relative to BG' 
is the same than the priority of one of the background layers, then the OBJ 
becomes higher priority and is displayed on top of that BG layer.<BR>Caution: 
Take care not to mess up BG Priority and OBJ priority. For example, the 
following would cause garbage to be displayed:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  OBJ No. 0 with Priority relative to BG=1   ;hi OBJ prio, lo BG prio
  OBJ No. 1 with Priority relative to BG=0   ;lo OBJ prio, hi BG prio
</PRE></TD></TR></TBODY></TABLE>That is, OBJ0 is always having priority above 
OBJ1-127, so assigning a lower BG Priority to OBJ0 than for OBJ1-127 would be a 
bad idea.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdobjoamrotationscalingparameters></A><FONT size=+2>&nbsp;LCD 
      OBJ - OAM Rotation/Scaling Parameters</FONT></TD></TR></TBODY></TABLE><BR>As 
described in the previous chapter, there are blank spaces between each of the 
128 OBJ Attribute Fields in OAM memory. These 128 16bit gaps are used to store 
OBJ Rotation/Scaling Parameters.<BR><BR><B>Location of Rotation/Scaling 
Parameters in OAM</B><BR>Four 16bit parameters (PA,PB,PC,PD) are required to 
define a complete group of Rotation/Scaling data. These are spread across OAM as 
such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1st Group - PA=07000006, PB=0700000E, PC=07000016, PD=0700001E
  2nd Group - PA=07000026, PB=0700002E, PC=07000036, PD=0700003E
  etc.
</PRE></TD></TR></TBODY></TABLE>By using all blank space (128 x 16bit), up to 32 
of these groups (4 x 16bit each) can be defined in OAM.<BR><BR><B>OBJ 
Rotation/Scaling PA,PB,PC,PD Parameters (R/W)</B><BR>Each OBJ that uses 
Rotation/Scaling may select between any of the above 32 parameter groups. For 
details, refer to the previous chapter about OBJ Attributes.<BR>The meaning of 
the separate PA,PB,PC,PD values is identical as for BG, for details read the 
chapter about BG Rotation/Scaling.<BR><BR><B>OBJ Reference Point &amp; Rotation 
Center</B><BR>The OBJ Reference Point is the upper left of the OBJ, ie. OBJ X/Y 
coordinates: X+0, Y+0.<BR>The OBJ Rotation Center is always (or should be 
usually?) in the middle of the object, ie. for a 8x32 pixel OBJ, this would be 
at the OBJ X/Y coordinates: X+4, and Y+16.<BR><BR><B>OBJ Double-Size Bit (for 
OBJs that use Rotation/Scaling)</B><BR>When Double-Size is zero: The sprite is 
rotated, and then display inside of the normal-sized (not rotated) rectangular 
area - the edges of the rotated sprite will become invisible if they reach 
outside of that area.<BR>When Double-Size is set: The sprite is rotated, and 
then display inside of the double-sized (not rotated) rectangular area - this 
ensures that the edges of the rotated sprite remain visible even if they would 
reach outside of the normal-sized area. (Except that, for example, rotating a 
8x32 pixel sprite by 90 degrees would still cut off parts of the sprite as the 
double-size area isn't large enough.)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdobjvramcharactertilemapping></A><FONT size=+2>&nbsp;LCD OBJ 
      - VRAM Character (Tile) Mapping</FONT></TD></TR></TBODY></TABLE><BR>Each OBJ 
tile consists of 8x8 dots, however, bigger OBJs can be displayed by combining 
several 8x8 tiles. The horizontal and vertical size for each OBJ may be 
separately defined in OAM, possible H/V sizes are 8,16,32,64 dots - allowing 
'square' OBJs to be used (such like 8x8, 16x16, etc) as well as 'rectangular' 
OBJs (such like 8x32, 64x16, etc.)<BR><BR>When displaying an OBJ that contains 
of more than one 8x8 tile, one of the following two mapping modes can be used. 
In either case, the tile number of the upperleft tile must be specified in OAM 
memory.<BR><BR><B>Two Dimensional Character Mapping (DISPCNT Bit 6 
cleared)</B><BR>This mapping mode assumes that the 1024 OBJ tiles are arranged 
as a matrix of 32x32 tiles / 256x256 pixels (In 256 color mode: 16x32 tiles / 
128x256 pixels). Ie. the upper row of this matrix contains tiles 00h-1Fh, the 
next row tiles 20h-3Fh, and so on.<BR>For example, when displaying a 16x16 pixel 
OBJ, with tile number set to 04h; The upper row of the OBJ will consist of tile 
04h and 05h, the next row of 24h and 25h. (In 256 color mode: 04h and 06h, 24h 
and 26h.)<BR><BR><B>One Dimensional Character Mapping (DISPCNT Bit 6 
set)</B><BR>In this mode, tiles are mapped each after each other from 
00h-3FFh.<BR>Using the same example as above, the upper row of the OBJ will 
consist of tile 04h and 05h, the next row of tile 06h and 07h. (In 256 color 
mode: 04h and 06h, 08h and 0Ah.)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcdcolorpalettes></A><FONT size=+2>&nbsp;LCD Color 
      Palettes</FONT></TD></TR></TBODY></TABLE><BR><B>Color Palette RAM</B><BR>BG and 
OBJ palettes are using separate memory regions:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  05000000-050001FF - BG Palette RAM (512 bytes, 256 colors)
  05000200-050003FF - OBJ Palette RAM (512 bytes, 256 colors)
</PRE></TD></TR></TBODY></TABLE>Each BG and OBJ palette RAM may be either split 
into 16 palettes with 16 colors each, or may be used as a single palette with 
256 colors.<BR>Note that some OBJs may access palette RAM in 16 color mode, 
while other OBJs may use 256 color mode at the same time. Same for BG0-BG3 
layers.<BR><BR><B>Transparent Colors</B><BR>Color 0 of all BG and OBJ palettes 
is transparent. Even though palettes are described as 16 (256) color palettes, 
only 15 (255) colors are actually visible.<BR><BR><B>Backdrop Color</B><BR>Color 
0 of BG Palette 0 is used as backdrop color. This color is displayed if an area 
of the screen is not covered by any non-transparent BG or OBJ 
dots.<BR><BR><B>Color Definitions</B><BR>Each color occupies two bytes (same as 
for 32768 color BG modes):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-4   Red Intensity   (0-31)
  5-9   Green Intensity (0-31)
  10-14 Blue Intensity  (0-31)
  15    Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>Intensities</B><BR>Under normal 
circumstances (light source/viewing angle), the intensities 0-14 are practically 
all black, and only intensities 15-31 are resulting in visible medium..bright 
colors.<BR><BR>Note: The intensity problem appears in the 8bit CGB 
"compatibility" mode either. The original CGB display produced the opposite 
effect: Intensities 0-14 resulted in dark..medium colors, and intensities 15-31 
resulted in bright colors. Any "medium" colors of CGB games will appear 
invisible/black on GBA hardware, and only very bright colors will be 
visible.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=lcddimensionsandtimings></A><FONT size=+2>&nbsp;LCD Dimensions 
      and Timings</FONT></TD></TR></TBODY></TABLE><BR><B>Horizontal 
Dimensions</B><BR>The drawing time for each dot is 4 CPU cycles.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Visible     240 dots,  57.221 us,    960 cycles - 78% of h-time
  H-Blanking   68 dots,  16.212 us,    272 cycles - 22% of h-time
  Total       308 dots,  73.433 us,   1232 cycles - ca. 13.620 kHz
</PRE></TD></TR></TBODY></TABLE>VRAM and Palette RAM may be accessed during 
H-Blanking. OAM can accessed only if "H-Blank Interval Free" bit in DISPCNT 
register is set.<BR><BR><B>Vertical Dimensions</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Visible (*) 160 lines, 11.749 ms, 197120 cycles - 70% of v-time
  V-Blanking   68 lines,  4.994 ms,  83776 cycles - 30% of v-time
  Total       228 lines, 16.743 ms, 280896 cycles - ca. 59.737 Hz
</PRE></TD></TR></TBODY></TABLE>All VRAM, OAM, and Palette RAM may be accessed 
during V-Blanking.<BR>Note that no H-Blank interrupts are generated within 
V-Blank period.<BR><BR><B>System Clock</B><BR>The system clock is 16.78MHz 
(16*1024*1024 Hz), one cycle is thus approx. 59.59ns.<BR><BR>(*) Even though 
vertical screen size is 160 lines, the upper 8 lines are not &lt;really&gt; 
visible, these lines are covered by a shadow when holding the GBA orientated 
towards a light source, the lines are effectively black - and should not be used 
to display important information.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundcontroller></A><FONT size=+2>&nbsp;GBA Sound 
      Controller</FONT></TD></TR></TBODY></TABLE><BR>The GBA supplies four 'analogue' 
sound channels for Tone and Noise (mostly compatible to CGB sound), as well as 
two 'digital' sound channels (which can be used to replay 8bit DMA sample 
data).<BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundchannel1tonesweep">GBA Sound 
Channel 1 - Tone &amp; Sweep</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundchannel2tone">GBA Sound 
Channel 2 - Tone</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundchannel3waveoutput">GBA Sound 
Channel 3 - Wave Output</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundchannel4noise">GBA Sound 
Channel 4 - Noise</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundchannelaandbdmasound">GBA 
Sound Channel A and B - DMA Sound</A><BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbasoundcontrolregisters">GBA Sound 
Control Registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacomparisonofcgbandgbasound">GBA 
Comparison of CGB and GBA Sound</A><BR><BR>The GBA includes only a single (mono) 
speaker built-in, each channel may be output to either left and/or right 
channels by using the external line-out connector (for stereo headphones, 
etc).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundchannel1tonesweep></A><FONT size=+2>&nbsp;GBA Sound 
      Channel 1 - Tone &amp; Sweep</FONT></TD></TR></TBODY></TABLE><BR><B>4000060h - 
SOUND1CNT_L (NR10) - Channel 1 Sweep register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-2   R/W  Number of sweep shift      (n=0-7)
  3     R/W  Sweep Frequency Direction  (0=Increase, 1=Decrease)
  4-6   R/W  Sweep Time; units of 7.8ms (0-7, min=7.8ms, max=54.7ms)
  7-15  -    Not used
</PRE></TD></TR></TBODY></TABLE>Sweep is disabled by setting Sweep Time to zero, 
if so, the direction bit should be set.<BR>The change of frequency (NR13,NR14) 
at each shift is calculated by the following formula where X(0) is initial freq 
&amp; X(t-1) is last freq:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  X(t) = X(t-1) +/- X(t-1)/2^n
</PRE></TD></TR></TBODY></TABLE><BR><B>4000062h - SOUND1CNT_H (NR11, NR12) - 
Channel 1 Duty/Len/Envelope (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-5   W    Sound length; units of (64-n)/256s  (0-63)
  6-7   R/W  Wave Pattern Duty                   (0-3, see below)
  8-10  R/W  Envelope Step-Time; units of n/64s  (1-7, 0=No Envelope)
  11    R/W  Envelope Direction                  (0=Decrease, 1=Increase)
  12-15 R/W  Initial Volume of envelope          (1-15, 0=No Sound)
</PRE></TD></TR></TBODY></TABLE>Wave Duty:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0: 12.5% ( -_______-_______-_______ )
  1: 25%   ( --______--______--______ )
  2: 50%   ( ----____----____----____ ) (normal)
  3: 75%   ( ------__------__------__ )
</PRE></TD></TR></TBODY></TABLE>The Length value is used only if Bit 6 in NR14 
is set.<BR><BR><B>4000064h - SOUND1CNT_X (NR13, NR14) - Channel 1 
Frequency/Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-10  W    Frequency; 131072/(2048-n)Hz  (0-2047)
  11-13 -    Not used
  14    R/W  Length Flag  (1=Stop output when length in NR11 expires)
  15    W    Initial      (1=Restart Sound)
  16-31 -    Not used
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundchannel2tone></A><FONT size=+2>&nbsp;GBA Sound Channel 
      2 - Tone</FONT></TD></TR></TBODY></TABLE><BR>This sound channel works exactly as 
channel 1, except that it doesn't have a Tone Envelope/Sweep 
Register.<BR><BR><B>4000068h - SOUND2CNT_L (NR21, NR22) - Channel 2 
Duty/Length/Envelope (R/W)</B><BR><B>400006Ah - Not used</B><BR><B>400006Ch - 
SOUND2CNT_H (NR23, NR24) - Channel 2 Frequency/Control (R/W)</B><BR>For details, 
refer to channel 1 description.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundchannel3waveoutput></A><FONT size=+2>&nbsp;GBA Sound 
      Channel 3 - Wave Output</FONT></TD></TR></TBODY></TABLE><BR>This channel can be 
used to output digital sound, the length of the sample buffer (Wave RAM) can be 
either 32 or 64 digits (4bit samples). This sound channel can be also used to 
output normal tones when initializing the Wave RAM by a square wave. This 
channel doesn't have a volume envelope register.<BR><BR><B>4000070h - 
SOUND3CNT_L (NR30) - Channel 3 Stop/Wave RAM select (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-4   -    Not used
  5     R/W  Wave RAM Dimension   (0=One bank/32 digits, 1=Two banks/64 digits)
  6     R/W  Wave RAM Bank Number (0-1, see below)
  7     R/W  Sound Channel 3 Off  (0=Stop, 1=Playback)
  8-15  -    Not used
</PRE></TD></TR></TBODY></TABLE>The currently selected Bank Number (Bit 6) will 
be played back, while reading/writing to/from wave RAM will address the other 
(not selected) bank. When dimension is set to two banks, output will start by 
replaying the currently selected bank.<BR><BR><B>4000072h - SOUND3CNT_H (NR31, 
NR32) - Channel 3 Length/Volume (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-7   W    Sound length; units of (256-n)/256s  (0-255)
  8-12  -    Not used.
  13-14 R/W  Sound Volume  (0=Mute/Zero, 1=100%, 2=50%, 3=25%)
  15    R/W  Force Volume  (0=Use above, 1=Force 75% regardless of above)
</PRE></TD></TR></TBODY></TABLE>The Length value is used only if Bit 6 in NR34 
is set.<BR><BR><B>4000074h - SOUND3CNT_X (NR33, NR34) - Channel 3 
Frequency/Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-10  W    Sample Rate; 2097152/(2048-n) Hz   (0-2047)
  11-13 -    Not used
  14    R/W  Length Flag  (1=Stop output when length in NR31 expires)
  15    W    Initial      (1=Restart Sound)
  16-31 -    Not used
</PRE></TD></TR></TBODY></TABLE>The above sample rate specifies the number of 
wave RAM digits per second, the actual tone frequency depends on the wave RAM 
content, for example:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Wave RAM, single bank 32 digits   Tone Frequency
  FFFFFFFFFFFFFFFF0000000000000000  65536/(2048-n) Hz
  FFFFFFFF00000000FFFFFFFF00000000  131072/(2048-n) Hz
  FFFF0000FFFF0000FFFF0000FFFF0000  262144/(2048-n) Hz
  FF00FF00FF00FF00FF00FF00FF00FF00  524288/(2048-n) Hz
  F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0  1048576/(2048-n) Hz
</PRE></TD></TR></TBODY></TABLE><BR><B>4000090h - WAVE_RAM0_L - Channel 3 Wave 
Pattern RAM (W/R)</B><BR><B>4000092h - WAVE_RAM0_H - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>4000094h - WAVE_RAM1_L - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>4000096h - WAVE_RAM1_H - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>4000098h - WAVE_RAM2_L - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>400009Ah - WAVE_RAM2_H - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>400009Ch - WAVE_RAM3_L - Channel 3 Wave Pattern RAM 
(W/R)</B><BR><B>400009Eh - WAVE_RAM3_H - Channel 3 Wave Pattern RAM 
(W/R)</B><BR>This area contains 16 bytes (32 x 4bits) Wave Pattern data which is 
output by channel 3. Data is played back ordered as follows: MSBs of 1st byte, 
followed by LSBs of 1st byte, followed by MSBs of 2nd byte, and so on - this 
results in a confusing ordering when filling Wave RAM in units of 16bit data - 
ie. samples would be then located in Bits 4-7, 0-3, 12-15, 8-11.<BR><BR>In the 
GBA, two Wave Patterns exists (each 32 x 4bits), either one may be played (as 
selected in NR30 register), the other bank may be accessed by the users. After 
all 32 samples have been played, output of the same bank (or other bank, as 
specified in NR30) will be automatically restarted.<BR><BR>Internally, Wave RAM 
is a giant shift-register, there is no pointer which is addressing the currently 
played digit. Instead, the entire 128 bits are shifted, and the 4 least 
significant bits are output.<BR>Thus, when reading from Wave RAM, data might 
have changed its position. And, when writing to Wave RAM all data should be 
updated (it'd be no good idea to assume that old data is still located at the 
same position where it has been written to previously).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundchannel4noise></A><FONT size=+2>&nbsp;GBA Sound 
      Channel 4 - Noise</FONT></TD></TR></TBODY></TABLE><BR>This channel is used to 
output white noise. This is done by randomly switching the amplitude between 
high and low at a given frequency. Depending on the frequency the noise will 
appear 'harder' or 'softer'.<BR><BR>It is also possible to influence the 
function of the random generator, so the that the output becomes more regular, 
resulting in a limited ability to output Tone instead of 
Noise.<BR><BR><B>4000078h - SOUND4CNT_L (NR41, NR42) - Channel 4 Length/Envelope 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-5   W    Sound length; units of (64-n)/256s  (0-63)
  6-7   -    Not used
  8-10  R/W  Envelope Step-Time; units of n/64s  (1-7, 0=No Envelope)
  11    R/W  Envelope Direction                  (0=Decrease, 1=Increase)
  12-15 R/W  Initial Volume of envelope          (1-15, 0=No Sound)
  16-31 -    Not used
</PRE></TD></TR></TBODY></TABLE>The Length value is used only if Bit 6 in NR44 
is set.<BR><BR><B>400007Ch - SOUND4CNT_H (NR43, NR44) - Channel 4 
Frequency/Control (R/W)</B><BR>The amplitude is randomly switched between high 
and low at the given frequency. A higher frequency will make the noise to appear 
'softer'.<BR>When Bit 3 is set, the output will become more regular, and some 
frequencies will sound more like Tone than Noise.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit        Expl.
  0-2   R/W  Dividing Ratio of Frequencies (r)
  3     R/W  Counter Step/Width (0=15 bits, 1=7 bits)
  4-7   R/W  Shift Clock Frequency (s)
  8-13  -    Not used
  14    R/W  Length Flag  (1=Stop output when length in NR41 expires)
  15    W    Initial      (1=Restart Sound)
  16-31 -    Not used
</PRE></TD></TR></TBODY></TABLE>Frequency = 524288 Hz / r / 2^(s+1) ;For r=0 
assume r=0.5 instead<BR><BR><B>Noise Random Generator (aka Polynomial 
Counter)</B><BR>Noise randomly switches between HIGH and LOW levels, the output 
levels are calculated by a shift register (X), at the selected frequency, as 
such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  7bit:  X=X SHR 1, IF carry THEN Out=HIGH, X=X XOR 60h ELSE Out=LOW
  15bit: X=X SHR 1, IF carry THEN Out=HIGH, X=X XOR 6000h ELSE Out=LOW
</PRE></TD></TR></TBODY></TABLE>The initial value when (re-)starting the sound 
is X=40h (7bit) or X=4000h (15bit). The data stream repeats after 7Fh (7bit) or 
7FFFh (15bit) steps.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundchannelaandbdmasound></A><FONT size=+2>&nbsp;GBA Sound 
      Channel A and B - DMA Sound</FONT></TD></TR></TBODY></TABLE><BR>The GBA contains 
two DMA sound channels (A and B), each allowing to replay digital sound (signed 
8bit data, ie. -128..+127). Data can be transferred from INTERNAL memory (not 
sure if EXTERNAL memory works also ?) to FIFO by using DMA channel 1 or 2, the 
sample rate is generated by using one of the Timers.<BR><BR><B>40000A0h - 
FIFO_A_L - Sound A FIFO, Data 0 and Data 1 (W)</B><BR><B>40000A2h - FIFO_A_H - 
Sound A FIFO, Data 2 and Data 3 (W)</B><BR>These two registers may receive 32bit 
(4 bytes) of audio data (Data 0-3, Data 0 being located in least significant 
byte which is replayed first).<BR>Internally, the capacity of the FIFO is 8 x 
32bit (32 bytes), allowing to buffer a small amount of samples. As the name says 
(First In First Out), oldest data is replayed first.<BR><BR><B>40000A4h - 
FIFO_B_L - Sound B FIFO, Data 0 and Data 1 (W)</B><BR><B>40000A6h - FIFO_B_H - 
Sound B FIFO, Data 2 and Data 3 (W)</B><BR>Same as above, for Sound 
B.<BR><BR><B>Initializing DMA-Sound Playback</B><BR>- Select Timer 0 or 1 in 
SOUNDCNT_H control register.<BR>- Clear the FIFO.<BR>- Manually write a sample 
byte to the FIFO.<BR>- Initialize transfer mode for DMA 1 or 2.<BR>- Initialize 
DMA Sound settings in sound control register.<BR>- Start the 
timer.<BR><BR><B>DMA-Sound Playback Procedure</B><BR>The pseudo-procedure below 
is automatically repeated.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  If Timer overflows then
    Move 8bit data from FIFO to sound circuit.
    If FIFO contains only 4 x 32bits (16 bytes) then
      Request more data per DMA
      Receive 4 x 32bit (16 bytes) per DMA
    Endif
  Endif
</PRE></TD></TR></TBODY></TABLE>This playback mechanism will be repeated 
forever, regardless of the actual length of the sample 
buffer.<BR><BR><B>Synchronizing Sample Buffers</B><BR>The buffer-end may be 
determined by counting sound Timer IRQs (each sample byte), or sound DMA IRQs 
(each 16th sample byte). Both methods would require a lot of CPU time (IRQ 
processing), and both would fail if interrupts are disabled for a longer 
period.<BR>Better solutions would be to synchronize the sample rate/buffer 
length with V-blanks, or to use a second timer (in count up/slave mode) which 
produces an IRQ after the desired number of samples.<BR><BR><B>The Sample 
Rate</B><BR>The GBA hardware does internally re-sample all sound output to 
32.768kHz (default SOUNDBIAS setting). It'd thus do not make much sense to use 
higher DMA/Timer rates. Best re-sampling accuracy can be gained by using 
DMA/Timer rates of 32.768kHz, 16.384kHz, or 8.192kHz (ie. fragments of the 
physical output rate).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasoundcontrolregisters></A><FONT size=+2>&nbsp;GBA Sound 
      Control Registers</FONT></TD></TR></TBODY></TABLE><BR><B>4000080h - SOUNDCNT_L 
(NR50, NR51) - Channel L/R Volume/Enable (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-2   Sound 1-4 Master Volume RIGHT (0-7)
  3     Not used
  4-6   Sound 1-4 Master Volume LEFT (0-7)
  7     Not used
  8-11  Sound 1-4 Enable Flags RIGHT (each Bit 8-11, 0=Disable, 1=Enable)
  12-15 Sound 1-4 Enable Flags LEFT (each Bit 12-15, 0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE><BR><B>4000082h - SOUNDCNT_H (GBA only) - DMA 
Sound Control/Mixing (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   Sound # 1-4 Volume   (0=25%, 1=50%, 2=100%, 3=Prohibited)
  2     DMA Sound A Volume   (0=50%, 1=100%)
  3     DMA Sound B Volume   (0=50%, 1=100%)
  4-7   Not used
  8     DMA Sound A Enable RIGHT (0=Disable, 1=Enable)
  9     DMA Sound A Enable LEFT  (0=Disable, 1=Enable)
  10    DMA Sound A Timer Select (0=Timer 0, 1=Timer 1)
  11    DMA Sound A Reset FIFO   (1=Reset)
  12    DMA Sound B Enable RIGHT (0=Disable, 1=Enable)
  13    DMA Sound B Enable LEFT  (0=Disable, 1=Enable)
  14    DMA Sound B Timer Select (0=Timer 0, 1=Timer 1)
  15    DMA Sound B Reset FIFO   (1=Reset)
</PRE></TD></TR></TBODY></TABLE><BR><B>4000084h - SOUNDCNT_X (NR52) - Sound 
on/off (R/W)</B><BR>Bits 0-3 are automatically set when starting sound output, 
and are automatically cleared when a sound ends. (Ie. when the length expires, 
as far as length is enabled. The bits are NOT reset when an volume envelope 
ends.)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Sound 1 ON flag (Read Only)
  1     Sound 2 ON flag (Read Only)
  2     Sound 3 ON flag (Read Only)
  3     Sound 4 ON flag (Read Only)
  4-6   Not used
  7     PSG/FIFO Master Enable (0=Disable, 1=Enable) (Read/Write)
  8-31  Not used
</PRE></TD></TR></TBODY></TABLE>While Bit 7 is cleared, both PSG and FIFO sounds 
are disabled, and all PSG registers (4000060h..4000081h) are reset to zero (and 
must be re-initialized after re-enabling sound). However, registers 4000082h and 
4000088h are kept read/write-able (of which, 4000082h has no function when sound 
is off, whilst 4000088h does work even when sound is off).<BR><BR><B>4000088h - 
SOUNDBIAS - Sound PWM Control (R/W, see below)</B><BR>This register controls the 
final sound output. The default setting is 0200h, it is normally not required to 
change this value.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  0-9    Bias Level     (Default=200h, converting signed samples into unsigned)
  10-13  Not used
  14-15  Amplitude Resolution/Sampling Cycle (Default=0, see below)
  16-31  Not used
</PRE></TD></TR></TBODY></TABLE>Amplitude Resolution/Sampling Cycle (0-3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  9bit / 32.768kHz   (Default, best for DMA channels A,B)
  1  8bit / 65.536kHz
  2  7bit / 131.072kHz
  3  6bit / 262.144kHz  (Best for PSG channels 1-4)
</PRE></TD></TR></TBODY></TABLE>For more information on this register, read the 
descriptions below.<BR><BR><B>400008Ch - Not used</B><BR><B>400008Eh - Not 
used</B><BR><BR><B>Max Output Levels (with max volume settings)</B><BR>Each of 
the two FIFOs can span the FULL output range (+/-200h).<BR>Each of the four PSGs 
can span one QUARTER of the output range (+/-80h).<BR>The current output levels 
of all six channels are added together by hardware.<BR>So together, the FIFOs 
and PSGs, could reach THRICE the range (+/-600h).<BR>The BIAS value is added to 
that signed value. With default BIAS (200h), the possible range becomes 
-400h..+800h, however, values that exceed the unsigned 10bit output range of 
0..3FFh are clipped to MinMax(0,3FFh).<BR><BR><B>Resampling to 32.768kHz / 9bit 
(default)</B><BR>The PSG channels 1-4 are internally generated at 262.144kHz, 
and DMA sound A-B could be theoretically generated at timer rates up to 
16.78MHz. However, the final sound output is resampled to a rate of 32.768kHz, 
at 9bit depth (the above 10bit value, divided by two). If necessary, rates 
higher than 32.768kHz can be selected in the SOUNDBIAS register, that would 
result in a depth smaller than 9bit though.<BR><BR><B>PWM (Pulse Width 
Modulation) Output 16.78MHz / 1bit</B><BR>Okay, now comes the actual output. The 
GBA can output only two voltages (low and high), these 'bits' are output at 
system clock speed (16.78MHz). If using the default 32.768kHz sampling rate, 
then 512 bits are output per sample (512*32K=16M). Each sample value (9bit 
range, N=0..511), would be then output as N low bits, followed by 512-N high 
bits. The resulting 'noise' is smoothed down by capacitors, by the speaker, and 
by human hearing, so that it will effectively sound like clean D/A converted 
9bit voltages at 32kHz sampling rate.<BR><BR><B>Changing the BIAS 
Level</B><BR>Normally use 200h for clean sound output. A value of 000h might 
make sense during periods when no sound is output (causing the PWM circuit to 
output low-bits only, which is eventually reducing the power consumption, and/or 
preventing 32KHz noise). Note: Using the SoundBias function (SWI 19h) allows to 
change the level by slowly incrementing or decrementing it (without hard scratch 
noise).<BR><BR><B>Low Power Mode</B><BR>When not using sound output, power 
consumption can be reduced by setting both 4000084h (PSG/FIFO) and 4000088h 
(BIAS) to zero.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacomparisonofcgbandgbasound></A><FONT size=+2>&nbsp;GBA 
      Comparison of CGB and GBA Sound</FONT></TD></TR></TBODY></TABLE><BR>The GBA 
sound controller is mostly the same than that of older monochrome gameboy and 
CGB. The following changes have been done:<BR><BR><B>New Sound 
Channels</B><BR>Two new sound channels have been added that may be used to 
replay 8bit digital sound. Sample rate and sample data must be supplied by using 
a Timer and a DMA channel.<BR><BR><B>New Control Registers</B><BR>The SOUNDCNT_H 
register controls the new DMA channels - as well as mixing with the four old 
channels. The SOUNDBIAS register controls the final sound 
output.<BR><BR><B>Sound Channel 3 Changes</B><BR>The length of the Wave RAM is 
doubled by dividing it into two banks of 32 digits each, either one or both 
banks may be replayed (one after each other), for details check NR30 Bit 5-6. 
Optionally, the sound may be output at 75% volume, for details check NR32 Bit 
7.<BR><BR><B>Changed Control Registers</B><BR>NR50 is not supporting Vin signals 
(that's been an external sound input from cartridge).<BR><BR><B>Changed I/O 
Addresses</B><BR>The GBAs sound register are located at 04000060-040000AE 
instead of at FF10-FF3F as in CGB and monochrome gameboy. However, note that 
there have been new blank spaces inserted between some of the separate registers 
- therefore it is NOT possible to port CGB software to GBA just by changing the 
sound base address.<BR><BR><B>Accessing I/O Registers</B><BR>In some cases two 
of the old 8bit registers are packed into a 16bit register and may be accessed 
as such.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbatimers></A><FONT size=+2>&nbsp;GBA 
  Timers</FONT></TD></TR></TBODY></TABLE><BR>The GBA includes four incrementing 
16bit timers.<BR>Timer 0 and 1 can be used to supply the sample rate for DMA 
sound channel A and/or B.<BR><BR><B>4000100h - TM0CNT_L - Timer 0 Counter/Reload 
(R/W)</B><BR><B>4000104h - TM1CNT_L - Timer 1 Counter/Reload 
(R/W)</B><BR><B>4000108h - TM2CNT_L - Timer 2 Counter/Reload 
(R/W)</B><BR><B>400010Ch - TM3CNT_L - Timer 3 Counter/Reload 
(R/W)</B><BR>Writing to these registers initializes the &lt;reload&gt; value 
(but does not directly affect the current counter value). Reading returns the 
current &lt;counter&gt; value (or the recent/frozen counter value if the timer 
has been stopped).<BR>The reload value is copied into the counter only upon 
following two situations: Automatically upon timer overflows, or when the timer 
start bit becomes changed from 0 to 1.<BR>Note: When simultaneously changing the 
start bit from 0 to 1, and setting the reload value at the same time (by a 
single 32bit I/O operation), then the newly written reload value is recognized 
as new counter value.<BR><BR><B>4000102h - TM0CNT_H - Timer 0 Control 
(R/W)</B><BR><B>4000106h - TM1CNT_H - Timer 1 Control (R/W)</B><BR><B>400010Ah - 
TM2CNT_H - Timer 2 Control (R/W)</B><BR><B>400010Eh - TM3CNT_H - Timer 3 Control 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)
  2     Count-up Timing   (0=Normal, 1=See below)
  3-5   Not used
  6     Timer IRQ Enable  (0=Disable, 1=IRQ on Timer overflow)
  7     Timer Start/Stop  (0=Stop, 1=Operate)
  8-15  Not used
</PRE></TD></TR></TBODY></TABLE>When Count-up Timing is enabled, the prescaler 
value is ignored, instead the time is incremented each time when the previous 
counter overflows. This function cannot be used for Timer 0 (as it is the first 
timer).<BR>F = System Clock (16.78MHz).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbadmatransfers></A><FONT size=+2>&nbsp;GBA DMA 
      Transfers</FONT></TD></TR></TBODY></TABLE><BR><B>Overview</B><BR>The GBA 
includes four DMA channels, the highest priority is assigned to DMA0, followed 
by DMA1, DMA2, and DMA3. DMA Channels with lower priority are paused until 
channels with higher priority have completed.<BR>The CPU is paused when DMA 
transfers are active, however, the CPU is operating during the periods when 
Sound/Blanking DMA transfers are paused.<BR><BR><B>Special features of the 
separate DMA channels</B><BR>DMA0 - highest priority, best for timing critical 
transfers (eg. HBlank DMA).<BR>DMA1 and DMA2 - can be used to feed digital 
sample data to the Sound FIFOs.<BR>DMA3 - can be used to write to Game Pak 
ROM/FlashROM (but not GamePak SRAM).<BR>Beside for that, each DMA 0-3 may be 
used for whatever general purposes.<BR><BR><B>40000B0h,0B2h - DMA0SAD - DMA 0 
Source Address (W) (internal memory)</B><BR><B>40000BCh,0BEh - DMA1SAD - DMA 1 
Source Address (W) (any memory)</B><BR><B>40000C8h,0CAh - DMA2SAD - DMA 2 Source 
Address (W) (any memory)</B><BR><B>40000D4h,0D6h - DMA3SAD - DMA 3 Source 
Address (W) (any memory)</B><BR>The most significant address bits are ignored, 
only the least significant 27 or 28 bits are used (max 07FFFFFFh internal 
memory, or max 0FFFFFFFh any memory - except SRAM ?!).<BR><BR><B>40000B4h,0B6h - 
DMA0DAD - DMA 0 Destination Address (W) (internal 
memory)</B><BR><B>40000C0h,0C2h - DMA1DAD - DMA 1 Destination Address (W) 
(internal memory)</B><BR><B>40000CCh,0CEh - DMA2DAD - DMA 2 Destination Address 
(W) (internal memory)</B><BR><B>40000D8h,0DAh - DMA3DAD - DMA 3 Destination 
Address (W) (any memory)</B><BR>The most significant address bits are ignored, 
only the least significant 27 or 28 bits are used (max. 07FFFFFFh internal 
memory or 0FFFFFFFh any memory - except SRAM ?!).<BR><BR><B>40000B8h - DMA0CNT_L 
- DMA 0 Word Count (W) (14 bit, 1..4000h)</B><BR><B>40000C4h - DMA1CNT_L - DMA 1 
Word Count (W) (14 bit, 1..4000h)</B><BR><B>40000D0h - DMA2CNT_L - DMA 2 Word 
Count (W) (14 bit, 1..4000h)</B><BR><B>40000DCh - DMA3CNT_L - DMA 3 Word Count 
(W) (16 bit, 1..10000h)</B><BR>Specifies the number of data units to be 
transferred, each unit is 16bit or 32bit depending on the transfer type, a value 
of zero is treated as max length (ie. 4000h, or 10000h for 
DMA3).<BR><BR><B>40000BAh - DMA0CNT_H - DMA 0 Control (R/W)</B><BR><B>40000C6h - 
DMA1CNT_H - DMA 1 Control (R/W)</B><BR><B>40000D2h - DMA2CNT_H - DMA 2 Control 
(R/W)</B><BR><B>40000DEh - DMA3CNT_H - DMA 3 Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-4   Not used
  5-6   Dest Addr Control  (0=Increment,1=Decrement,2=Fixed,3=Increment/Reload)
  7-8   Source Adr Control (0=Increment,1=Decrement,2=Fixed,3=Prohibited)
  9     DMA Repeat                   (0=Off, 1=On) (Must be zero if Bit 11 set)
  10    DMA Transfer Type            (0=16bit, 1=32bit)
  11    Game Pak DRQ  - DMA3 only -  (0=Normal, 1=DRQ &lt;from&gt; Game Pak, DMA3)
  12-13 DMA Start Timing  (0=Immediately, 1=VBlank, 2=HBlank, 3=Special)
          The 'Special' setting (Start Timing=3) depends on the DMA channel:
          DMA0=Prohibited, DMA1/DMA2=Sound FIFO, DMA3=Video Capture
  14    IRQ upon end of Word Count   (0=Disable, 1=Enable)
  15    DMA Enable                   (0=Off, 1=On)
</PRE></TD></TR></TBODY></TABLE>After changing the Enable bit from 0 to 1, wait 
2 clock cycles before accessing any DMA related registers.<BR><BR>When accessing 
OAM (7000000h) or OBJ VRAM (6010000h) by HBlank Timing, then the "H-Blank 
Interval Free" bit in DISPCNT register must be set.<BR><BR><B>Source and 
Destination Address and Word Count Registers</B><BR>The SAD, DAD, and CNT_L 
registers are holding the initial start addresses, and initial length. The 
hardware does NOT change the content of these registers during or after the 
transfer.<BR>The actual transfer takes place by using internal pointer/counter 
registers. The initial values are copied into internal regs under the following 
circumstances:<BR>Upon DMA Enable (Bit 15) changing from 0 to 1: Reloads SAD, 
DAD, CNT_L.<BR>Upon Repeat: Reloads CNT_L, and optionally DAD 
(Increment+Reload).<BR><BR><B>DMA Repeat bit</B><BR>If the Repeat bit is 
cleared: The Enable bit is automatically cleared after the specified number of 
data units has been transferred.<BR>If the Repeat bit is set: The Enable bit 
remains set after the transfer, and the transfer will be restarted each time 
when the Start condition (eg. HBlank, Fifo) becomes true. The specified number 
of data units is transferred &lt;each&gt; time when the transfer is 
(re-)started. The transfer will be repeated forever, until it gets stopped by 
software.<BR><BR><B>Sound DMA (FIFO Timing Mode) (DMA1 and DMA2 only)</B><BR>In 
this mode, the DMA Repeat bit must be set, and the destination address must be 
FIFO_A (040000A0h) or FIFO_B (040000A4h).<BR>Upon DMA request from sound 
controller, 4 units of 32bits (16 bytes) are transferred (both Word Count 
register and DMA Transfer Type bit are ignored). The destination address will 
not be incremented in FIFO mode.<BR>Keep in mind that DMA channels of higher 
priority may offhold sound DMA. For example, when using a 64 kHz sample rate, 16 
bytes of sound DMA data are requested each 0.25ms (4 kHz), at this time another 
16 bytes are still in the FIFO so that there's still 0.25ms time to satisfy the 
DMA request. Thus DMAs with higher priority should not be operated for longer 
than 0.25ms. (This problem does not arise for HBlank transfers as HBlank time is 
limited to 16.212us.)<BR><BR><B>Game Pak DMA</B><BR>Only DMA 3 may be used to 
transfer data to/from Game Pak ROM or Flash ROM - it cannot access Game Pak SRAM 
though (as SRAM data bus is limited to 8bit units). In normal mode, DMA is 
requested as long until Word Count becomes zero. When setting the 'Game Pack 
DRQ' bit, then the cartridge must contain an external circuit which outputs a 
/DREQ signal. Note that there is only one pin for /DREQ and /IREQ, thus the 
cartridge may not supply /IREQs while using DRQ mode.<BR><BR><B>Video Capture 
Mode (DMA3 only)</B><BR>Intended to copy a bitmap from memory (or from external 
hardware/camera) to VRAM. When using this transfer mode, set the repeat bit, and 
write the number of data units (per scanline) to the word count register. 
Capture works similar like HBlank DMA, however, the transfer is started when 
VCOUNT=2, it is then repeated each scanline, and it gets stopped when 
VCOUNT=162.<BR><BR><B>Transfer End</B><BR>The DMA Enable flag (Bit 15) is 
automatically cleared upon completion of the transfer. The user may also clear 
this bit manually in order to stop the transfer (obviously this is possible for 
Sound/Blanking DMAs only, in all other cases the CPU is stopped until the 
transfer completes by itself).<BR><BR><B>Transfer Rate/Timing</B><BR>Except for 
the first data unit, all units are transferred by sequential reads and writes. 
For n data units, the DMA transfer time is:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2N+2(n-1)S+xI
</PRE></TD></TR></TBODY></TABLE>Of which, 1N+(n-1)S are read cycles, and the 
other 1N+(n-1)S are write cycles, actual number of cycles depends on the 
waitstates and bus-width of the source and destination areas (as described in 
CPU Instruction Cycle Times chapter). Internal time for DMA processing is 2I 
(normally), or 4I (if both source and destination are in gamepak memory 
area).<BR><BR>DMA lockup when stopping while starting ???<BR>Capture delayed, 
Capture Enable=AutoCleared ???<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacommunicationports></A><FONT size=+2>&nbsp;GBA 
      Communication Ports</FONT></TD></TR></TBODY></TABLE><BR>The GBAs Serial Port may 
be used in various different communication modes. Normal mode may exchange data 
between two GBAs (or to transfer data from master GBA to several slave GBAs in 
one-way direction).<BR>Multi-player mode may exchange data between up to four 
GBAs. UART mode works much like a RS232 interface. JOY Bus mode uses a 
standardized Nintendo protocol. And General Purpose mode allows to mis-use the 
'serial' port as bi-directional 4bit parallel port.<BR>Note: The Nintendo DS 
does not include a Serial Port.<BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#sionormalmode">SIO Normal 
Mode</A><BR><A href="http://nocash.emubase.de/gbatek.htm#siomultiplayermode">SIO 
Multi-Player Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#siouartmode">SIO UART Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#siojoybusmode">SIO JOY BUS 
Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#siogeneralpurposemode">SIO 
General-Purpose Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#siocontrolregisterssummary">SIO 
Control Registers Summary</A><BR><BR><B>Infrared Communication 
Adapters</B><BR>Even though early GBA prototypes have been intended to support 
IR communication, this feature has been removed.<BR>However, Nintendo is 
apparently considering to provide an external IR adapter (to be connected to the 
SIO connector, being accessed in General Purpose mode).<BR>Also, it'd be 
theoretically possible to include IR ports built-in in game cartridges (as done 
for some older 8bit/monochrome Hudson games).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=sionormalmode></A><FONT size=+2>&nbsp;SIO Normal 
  Mode</FONT></TD></TR></TBODY></TABLE><BR>This mode is used to communicate 
between two units.<BR>Transfer rates of 256Kbit/s or 2Mbit/s can be selected, 
however, the fast 2Mbit/s is intended ONLY for special hardware expansions that 
are DIRECTLY connected to the GBA link port (ie. without a cable being located 
between the GBA and expansion hardware). In normal cases, always use 256Kbit/s 
transfer rate which provides stable results.<BR>Transfer lengths of 8bit or 
32bit may be used, the 8bit mode is the same as for older DMG/CGB gameboys, 
however, the voltages for "GBA cartridges in GBAs" are different as for "DMG/CGB 
cartridges in DMG/CGB/GBAs", ie. it is not possible to communicate between 
DMG/CGB games and GBA games.<BR><BR><B>4000134h - RCNT (R) - Mode Selection, in 
Normal/Multiplayer/UART modes (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Undocumented (current SC,SD,SI,SO state, as for General Purpose mode)
  4-8   Not used     (Should be 0, bits are read/write-able though)
  9-13  Not used     (Always 0, read only)
  14    Not used     (Should be 0, bit is read/write-able though)
  15    Must be zero (0) for Normal/Multiplayer/UART modes
</PRE></TD></TR></TBODY></TABLE><BR><B>4000128h - SIOCNT - SIO Control, usage in 
NORMAL Mode (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Shift Clock (SC)        (0=External, 1=Internal)
  1     Internal Shift Clock    (0=256KHz, 1=2MHz)
  2     SI State (opponents SO) (0=Low, 1=High/None) --- (Read Only)
  3     SO during inactivity    (0=Low, 1=High) (applied ONLY when Bit7=0)
  4-6   Not used                (Read only, always 0 ?)
  7     Start Bit               (0=Inactive/Ready, 1=Start/Active)
  8-11  Not used                (R/W, should be 0)
  12    Transfer Length         (0=8bit, 1=32bit)
  13    Must be "0" for Normal Mode
  14    IRQ Enable              (0=Disable, 1=Want IRQ upon completion)
  15    Not used                (Read only, always 0)
</PRE></TD></TR></TBODY></TABLE>The Start bit is automatically reset when the 
transfer completes, ie. when all 8 or 32 bits are transferred, at that time an 
IRQ may be generated.<BR><BR><B>400012Ah - SIODATA8 - SIO Normal Communication 
8bit Data (R/W)</B><BR>For 8bit normal mode. Contains 8bit data (only lower 8bit 
are used). Outgoing data should be written to this register before starting the 
transfer. During transfer, transmitted bits are shifted-out (MSB first), and 
received bits are shifted-in simultaneously. Upon transfer completion, the 
register contains the received 8bit value.<BR><BR><B>4000120h - SIODATA32_L - 
SIO Normal Communication lower 16bit data (R/W)</B><BR><B>4000122h - SIODATA32_H 
- SIO Normal Communication upper 16bit data (R/W)</B><BR>Same as above SIODATA8, 
for 32bit normal transfer mode respectively.<BR>SIOCNT/RCNT must be set to 32bit 
normal mode &lt;before&gt; writing to 
SIODATA32.<BR><BR><B>Initialization</B><BR>First, initialize RCNT register. 
Second, set mode/clock bits in SIOCNT with startbit cleared. For master: select 
internal clock, and (in most cases) specify 256KHz as transfer rate. For slave: 
select external clock, the local transfer rate selection is then ignored, as the 
transfer rate is supplied by the remote GBA (or other computer, which might 
supply custom transfer rates).<BR>Third, set the startbit in SIOCNT with 
mode/clock bits unchanged.<BR><BR><B>Recommended Communication Procedure for 
SLAVE unit (external clock)</B><BR>- Initialize data which is to be sent to 
master.<BR>- Set Start flag.<BR>- Set SO to LOW to indicate that master may 
start now.<BR>- Wait for IRQ (or for Start bit to become zero). (Check timeout 
here!)<BR>- Set SO to HIGH to indicate that we are not ready.<BR>- Process 
received data.<BR>- Repeat procedure if more data is to be transferred.<BR>(or 
is so=high done automatically? would be fine - more stable - otherwise master 
may still need delay)<BR><BR><B>Recommended Communication Procedure for SLAVE 
unit (external clock)</B><BR>- Initialize data which is to be sent to 
master.<BR>- Set Start=0 and SO=0 (SO=LOW indicates that slave is (almost) 
ready).<BR>- Set Start=1 and SO=1 (SO=HIGH indicates not ready, applied after 
transfer).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  (Expl. Old SO=LOW kept output until 1st clock bit received).
  (Expl. New SO=HIGH is automatically output at transfer completion).
</PRE></TD></TR></TBODY></TABLE>- Set SO to LOW to indicate that master may 
start now.<BR>- Wait for IRQ (or for Start bit to become zero). (Check timeout 
here!)<BR>- Process received data.<BR>- Repeat procedure if more data is to be 
transferred.<BR><BR><B>Recommended Communication Procedure for MASTER unit 
(internal clock)</B><BR>- Initialize data which is to be sent to slave.<BR>- 
Wait for SI to become LOW (slave ready). (Check timeout here!)<BR>- Set Start 
flag.<BR>- Wait for IRQ (or for Start bit to become zero).<BR>- Process received 
data.<BR>- Repeat procedure if more data is to be transferred.<BR><BR><B>Cable 
Protocol</B><BR>During inactive transfer, the shift clock (SC) is high. The 
transmit (SO) and receive (SI) data lines may be manually controlled as 
described above.<BR>When master sends SC=LOW, each master and slave must output 
the next outgoing data bit to SO. When master sends SC=HIGH, each master and 
slave must read out the opponents data bit from SI. This is repeated for each of 
the 8 or 32 bits, and when completed SC will be kept high 
again.<BR><BR><B>Transfer Rates</B><BR>Either 256KHz or 2MHz rates can be 
selected for SC, so max 32KBytes (256Kbit) or 128KBytes (2Mbit) can be 
transferred per second. However, the software must process each 8bit or 32bit of 
transmitted data separately, so the actual transfer rate will be reduced by the 
time spent on handling each data unit.<BR>Only 256KHz provides stable results in 
most cases (such like when linking between two GBAs). The 2MHz rate is intended 
for special expansion hardware (with very short wires) only.<BR><BR><B>Using 
Normal mode for One-Way Multiplayer communication</B><BR>When using normal mode 
with multiplay-cables, data isn't exchanged between first and second GBA as 
usually. Instead, data is shifted from first to last GBA (the first GBA receives 
zero, because master SI is shortcut to GND).<BR>This behaviour may be used for 
fast ONE-WAY data transfer from master to all other GBAs. For example (3 GBAs 
linked):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Step         Sender      1st Recipient   2nd Recipient
  Transfer 1:  DATA #0 --&gt; UNDEF      --&gt;  UNDEF     --&gt;
  Transfer 2:  DATA #1 --&gt; DATA #0    --&gt;  UNDEF     --&gt;
  Transfer 3:  DATA #2 --&gt; DATA #1    --&gt;  DATA #0   --&gt;
  Transfer 4:  DATA #3 --&gt; DATA #2    --&gt;  DATA #1   --&gt;
</PRE></TD></TR></TBODY></TABLE>The recipients should not output any own data, 
instead they should forward the previously received data to the next recipient 
during next transfer (just keep the incoming data unmodified in the data 
register).<BR>Due to the delayed forwarding, 2nd recipient should ignore the 
first incoming data. After the last transfer, the sender must send one (or more) 
dummy data unit(s), so that the last data is forwarded to the 2nd (or further) 
recipient(s).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=siomultiplayermode></A><FONT size=+2>&nbsp;SIO Multi-Player 
      Mode</FONT></TD></TR></TBODY></TABLE><BR>Multi-Player mode can be used to 
communicate between up to 4 units.<BR><BR><B>4000134h - RCNT (R) - Mode 
Selection, in Normal/Multiplayer/UART modes (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Undocumented (current SC,SD,SI,SO state, as for General Purpose mode)
  4-8   Not used     (Should be 0, bits are read/write-able though)
  9-13  Not used     (Always 0, read only)
  14    Not used     (Should be 0, bit is read/write-able though)
  15    Must be zero (0) for Normal/Multiplayer/UART modes
</PRE></TD></TR></TBODY></TABLE>Note: Even though undocumented, many Nintendo 
games are using Bit 0 to test current SC state in multiplay 
mode.<BR><BR><B>4000128h - SIOCNT - SIO Control, usage in MULTI-PLAYER Mode 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   Baud Rate     (0-3: 9600,38400,57600,115200 bps)
  2     SI-Terminal   (0=Parent, 1=Child)                  (Read Only)
  3     SD-Terminal   (0=Bad connection, 1=All GBAs Ready) (Read Only)
  4-5   Multi-Player ID     (0=Parent, 1-3=1st-3rd child)  (Read Only)
  6     Multi-Player Error  (0=Normal, 1=Error)            (Read Only)
  7     Start/Busy Bit      (0=Inactive, 1=Start/Busy) (Read Only for Slaves)
  8-11  Not used            (R/W, should be 0)
  12    Must be "0" for Multi-Player mode
  13    Must be "1" for Multi-Player mode
  14    IRQ Enable          (0=Disable, 1=Want IRQ upon completion)
  15    Not used            (Read only, always 0)
</PRE></TD></TR></TBODY></TABLE>The ID Bits are undefined until the first 
transfer has completed.<BR><BR><B>400012Ah - SIOMLT_SEND - Data Send Register 
(R/W)</B><BR>Outgoing data (16 bit) which is to be sent to the other 
GBAs.<BR><BR><B>4000120h - SIOMULTI0 - SIO Multi-Player Data 0 (Parent) 
(R/W)</B><BR><B>4000122h - SIOMULTI1 - SIO Multi-Player Data 1 (1st child) 
(R/W)</B><BR><B>4000124h - SIOMULTI2 - SIO Multi-Player Data 2 (2nd child) 
(R/W)</B><BR><B>4000126h - SIOMULTI3 - SIO Multi-Player Data 3 (3rd child) 
(R/W)</B><BR>These registers are automatically reset to FFFFh upon transfer 
start.<BR>After transfer, these registers contain incoming data (16bit each) 
from all remote GBAs (if any / otherwise still FFFFh), as well as the local 
outgoing SIOMLT_SEND data.<BR>Ie. after the transfer, all connected GBAs will 
contain the same values in their SIOMULTI0-3 
registers.<BR><BR><B>Initialization</B><BR>- Initialize RCNT Bit 14-15 and 
SIOCNT Bit 12-13 to select Multi-Player mode.<BR>- Read SIOCNT Bit 3 to verify 
that all GBAs are in Multi-Player mode.<BR>- Read SIOCNT Bit 2 to detect whether 
this is the Parent/Master unit.<BR><BR><B>Recommended Transmission 
Procedure</B><BR>- Write outgoing data to SIODATA_SEND.<BR>- Master must set 
Start bit.<BR>- All units must process received data in SIOMULTI0-3 when 
transfer completed.<BR>- After the first successful transfer, ID Bits in SIOCNT 
are valid.<BR>- If more data is to be transferred, repeat procedure.<BR>The 
parent unit blindly sends data regardless of whether childs have already 
processed old data/supplied new data. So, parent unit might be required to 
insert delays between each transfer, and/or perform error checking.<BR>Also, 
slave units may signalize that they are not ready by temporarily switching into 
another communication mode (which does not output SD High, as Multi-Player mode 
does during inactivity).<BR><BR><B>Transfer Protocol</B><BR>Beginning<BR>- The 
masters SI pin is always LOW.<BR>- When all GBAs are in Multiplayer mode (ready) 
SD is HIGH.<BR>- When master starts the transfer, it sets SC=LOW, slaves receive 
Busy bit.<BR>Step A<BR>- ID Bits in master unit are set to 0.<BR>- Master 
outputs Startbit (LOW), 16bit Data, Stopbit (HIGH) through SD.<BR>- This data is 
written to SIOMULTI0 of all GBAs (including master).<BR>- Master forwards LOW 
from its SO to 1st childs SI.<BR>- Transfer ends if next child does not output 
data after certain time.<BR>Step B<BR>- ID Bits in 1st child unit are set to 
1.<BR>- 1st Child outputs Startbit (LOW), 16bit Data, Stopbit (HIGH) through 
SD.<BR>- This data is written to SIOMULTI1 of all GBAs (including 1st 
child).<BR>- 1st child forwards LOW from its SO to 2nd childs SI.<BR>- Transfer 
ends if next child does not output data after certain time.<BR>Step C<BR>- ID 
Bits in 2nd child unit are set to 2.<BR>- 2nd Child outputs Startbit (LOW), 
16bit Data, Stopbit (HIGH) through SD.<BR>- This data is written to SIOMULTI2 of 
all GBAs (including 2nd child).<BR>- 2nd child forwards LOW from its SO to 3rd 
childs SI.<BR>- Transfer ends if next child does not output data after certain 
time.<BR>Step D<BR>- ID Bits in 3rd child unit are set to 3.<BR>- 3rd Child 
outputs Startbit (LOW), 16bit Data, Stopbit (HIGH) through SD.<BR>- This data is 
written to SIOMULTI3 of all GBAs (including 3rd child).<BR>- Transfer ends (this 
was the last child).<BR>Transfer end<BR>- Master sets SC=HIGH, all GBAs set 
SO=HIGH.<BR>- The Start/Busy bits of all GBAs are automatically cleared.<BR>- 
Interrupts are requested in all GBAs (as far as enabled).<BR><BR><B>Error 
Bit</B><BR>This bit is set when a slave did not receive SI=LOW even though 
SC=LOW signalized a transfer (this might happen when connecting more than 4 
GBAs, or when the previous child is not connected). Also, the bit is set when a 
Stopbit wasn't HIGH.<BR>The error bit may be undefined during active transfer - 
read only after transfer completion (the transfer continues and completes as 
normal even if errors have occurred for some or all GBAs).<BR>Don't know: The 
bit is automatically reset/initialized with each transfer, or must be manually 
reset?<BR><BR><B>Transmission Time</B><BR>The transmission time depends on the 
selected Baud rate. And on the amount of Bits (16 data bits plus start/stop bits 
for each GBA), delays between data for each GBA, plus final timeout (if less 
than 4 GBAs). That is, depending on the number of connected GBAs:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GBAs    Bits    Delays   Timeout
  1       18      None     Yes
  2       36      1        Yes
  3       54      2        Yes
  4       72      3        None
</PRE></TD></TR></TBODY></TABLE>(The average Delay and Timeout periods are 
unknown?)<BR>Above is not counting the additional CPU time that must be spent on 
initiating and processing each transfer.<BR><BR><B>Fast One-Way 
Transmission</B><BR>Beside for the actual SIO Multiplayer mode, you can also use 
SIO Normal mode for fast one-way data transfer from Master unit to all Child 
unit(s). See chapter about SIO Normal mode for details.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=siouartmode></A><FONT size=+2>&nbsp;SIO UART 
  Mode</FONT></TD></TR></TBODY></TABLE><BR>This mode works much like a RS232 port, 
however, the voltages are unknown, probably 0/3V rather than +/-12V ?. SI and SO 
are data lines (with crossed wires), SC and SD signalize Clear to Send (with 
crossed wires also, which requires special cable when linking between two GBAs 
?)<BR><BR><B>4000134h - RCNT (R) - Mode Selection, in Normal/Multiplayer/UART 
modes (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Undocumented (current SC,SD,SI,SO state, as for General Purpose mode)
  4-8   Not used     (Should be 0, bits are read/write-able though)
  9-13  Not used     (Always 0, read only)
  14    Not used     (Should be 0, bit is read/write-able though)
  15    Must be zero (0) for Normal/Multiplayer/UART modes
</PRE></TD></TR></TBODY></TABLE><BR><B>4000128h - SCCNT_L - SIO Control, usage 
in UART Mode (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   Baud Rate  (0-3: 9600,38400,57600,115200 bps)
  2     CTS Flag   (0=Send always/blindly, 1=Send only when SC=LOW)
  3     Parity Control (0=Even, 1=Odd)
  4     Send Data Flag      (0=Not Full,  1=Full)    (Read Only)
  5     Receive Data Flag   (0=Not Empty, 1=Empty)   (Read Only)
  6     Error Flag          (0=No Error,  1=Error)   (Read Only)
  7     Data Length         (0=7bits,   1=8bits)
  8     FIFO Enable Flag    (0=Disable, 1=Enable)
  9     Parity Enable Flag  (0=Disable, 1=Enable)
  10    Send Enable Flag    (0=Disable, 1=Enable)
  11    Receive Enable Flag (0=Disable, 1=Enable)
  12    Must be "1" for UART mode
  13    Must be "1" for UART mode
  14    IRQ Enable          (0=Disable, 1=IRQ when any Bit 4/5/6 become set)
  15    Not used            (Read only, always 0)
</PRE></TD></TR></TBODY></TABLE><BR><B>400012Ah - SIODATA8 - usage in UART Mode 
(R/W)</B><BR>Addresses the send/receive shift register, or (when FIFO is used) 
the send/receive FIFO. In either case only the lower 8bit of SIODATA8 are used, 
the upper 8bit are not used.<BR>The send/receive FIFO may store up to four 8bit 
data units each. For example, while 1 unit is still transferred from the send 
shift register, it is possible to deposit another 4 units in the send FIFO, 
which are then automatically moved to the send shift register one after each 
other.<BR><BR><B>Send/Receive Enable, CTS Feedback</B><BR>The receiver outputs 
SD=LOW (which is input as SC=LOW at the remote side) when it is ready to receive 
data (that is, when Receive Enable is set, and the Receive shift register (or 
receive FIFO) isn't full.<BR>When CTS flag is set to always/blindly, then the 
sender transmits data immediately when Send Enable is set, otherwise data is 
transmitted only when Send Enable is set and SC is LOW.<BR><BR><B>Error 
Flag</B><BR>The error flag is set when a bad stop bit has been received (stop 
bit must be 0), when a parity error has occurred (if enabled), or when new data 
has been completely received while the receive data register (or receive FIFO) 
is already full.<BR>The error flag is automatically reset when reading from 
SIOCNT register.<BR><BR><B>Init &amp; Initback</B><BR>The content of the FIFO is 
reset when FIFO is disabled in UART mode, thus, when entering UART mode 
initially set FIFO=disabled.<BR>The Send/Receive enable bits must be reset 
before switching from UART mode into another SIO mode!<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=siojoybusmode></A><FONT size=+2>&nbsp;SIO JOY BUS 
    Mode</FONT></TD></TR></TBODY></TABLE><BR>This communication mode uses Nintendo's 
standardized JOY Bus protocol. When using this communication mode, the GBA is 
always operated as SLAVE!<BR><BR>In this mode, SI and SO pins are data lines 
(apparently synchronized by Start/Stop bits?), SC and SD are set to low 
(including during active transfer?), the transfer rate is 
unknown?<BR><BR><B>4000134h - RCNT (R) - Mode Selection, in JOY BUS mode 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-3   Undocumented (current SC,SD,SI,SO state, as for General Purpose mode)
  4-8   Not used     (Should be 0, bits are read/write-able though)
  9-13  Not used     (Always 0, read only)
  14    Must be "1" for JOY BUS Mode
  15    Must be "1" for JOY BUS Mode
</PRE></TD></TR></TBODY></TABLE><BR><B>4000128h - SIOCNT - SIO Control, not used 
in JOY BUS Mode</B><BR>This register is not used in JOY BUS 
mode.<BR><BR><B>4000140h - JOYCNT - JOY BUS Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Device Reset Flag     (Command FFh)          (Read/Acknowledge)
  1     Receive Complete Flag (Command 14h or 15h?)  (Read/Acknowledge)
  2     Send Complete Flag    (Command 15h or 14h?)  (Read/Acknowledge)
  3-5   Not used
  6     IRQ when receiving a Device Reset Command  (0=Disable, 1=Enable)
  7-15  Not used
</PRE></TD></TR></TBODY></TABLE>Bit 0-2 are working much like the bits in the IF 
register: Write a "1" bit to reset (acknowledge) the respective bit.<BR>UNCLEAR: 
Interrupts can be requested for Send/Receive commands also?<BR><BR><B>4000150h - 
JOY_RECV_L - Receive Data Register low (R/W)</B><BR><B>4000152h - JOY_RECV_H - 
Receive Data Register high (R/W)</B><BR><B>4000154h - JOY_TRANS_L - Send Data 
Register low (R/W)</B><BR><B>4000156h - JOY_TRANS_H - Send Data Register high 
(R/W)</B><BR>Send/receive data registers.<BR><BR><B>4000158h - JOYSTAT - Receive 
Status Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Not used
  1     Receive Status Flag   (0=Remote GBA is/was receiving) (Read Only?)
  2     Not used
  3     Send Status Flag      (1=Remote GBA is/was sending)   (Read Only?)
  4-5   General Purpose Flag  (Not assigned, may be used for whatever purpose)
  6-15  Not used
</PRE></TD></TR></TBODY></TABLE>Bit 1 is automatically set when writing to local 
JOY_TRANS.<BR>Bit 3 is automatically reset when reading from local 
JOY_RECV.<BR><BR>Below are the four possible commands which can be received by 
the GBA. Note that the GBA (slave) cannot send any commands itself, all it can 
do is to read incoming data, and to provide 'reply' data which may (or may not) 
be read out by the master unit.<BR><BR><B>Command FFh - Device Reset</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Receive FFh (Command)
  Send    00h (GBA Type number LSB (or MSB?))
  Send    04h (GBA Type number MSB (or LSB?))
  Send    XXh (lower 8bits of SIOSTAT register)
</PRE></TD></TR></TBODY></TABLE><BR><B>Command 00h - Type/Status Data 
Request</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Receive 00h (Command)
  Send    00h (GBA Type number LSB (or MSB?))
  Send    04h (GBA Type number MSB (or LSB?))
  Send    XXh (lower 8bits of SIOSTAT register)
</PRE></TD></TR></TBODY></TABLE><BR><B>Command 15h - GBA Data Write (to 
GBA)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Receive 15h (Command)
  Receive XXh (Lower 8bits of JOY_RECV_L)
  Receive XXh (Upper 8bits of JOY_RECV_L)
  Receive XXh (Lower 8bits of JOY_RECV_H)
  Receive XXh (Upper 8bits of JOY_RECV_H)
  Send    XXh (lower 8bits of SIOSTAT register)
</PRE></TD></TR></TBODY></TABLE><BR><B>Command 14h - GBA Data Read (from 
GBA)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Receive 14h (Command)
  Send    XXh (Lower 8bits of JOY_TRANS_L)
  Send    XXh (Upper 8bits of JOY_TRANS_L)
  Send    XXh (Lower 8bits of JOY_TRANS_H)
  Send    XXh (Upper 8bits of JOY_TRANS_H)
  Send    XXh (lower 8bits of SIOSTAT register)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=siogeneralpurposemode></A><FONT size=+2>&nbsp;SIO 
      General-Purpose Mode</FONT></TD></TR></TBODY></TABLE><BR>In this mode, the SIO 
is 'misused' as a 4bit bi-directional parallel port, each of the SI,SO,SC,SD 
pins may be directly controlled, each can be separately declared as input (with 
internal pull-up) or as output signal.<BR><BR><B>4000134h - RCNT (R) - SIO Mode, 
usage in GENERAL-PURPOSE Mode (R/W)</B><BR>Interrupts can be requested when SI 
changes from HIGH to LOW, as General Purpose mode does not require a serial 
shift clock, this interrupt may be produced even when the GBA is in Stop (low 
power standby) state.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     SC Data Bit         (0=Low, 1=High)
  1     SD Data Bit         (0=Low, 1=High)
  2     SI Data Bit         (0=Low, 1=High)
  3     SO Data Bit         (0=Low, 1=High)
  4     SC Direction        (0=Input, 1=Output)
  5     SD Direction        (0=Input, 1=Output)
  6     SI Direction        (0=Input, 1=Output, but see below)
  7     SO Direction        (0=Input, 1=Output)
  8     SI Interrupt Enable (0=Disable, 1=Enable)
  9-13  Not used
  14    Must be "0" for General-Purpose Mode
  15    Must be "1" for General-Purpose or JOYBUS Mode
</PRE></TD></TR></TBODY></TABLE>SI should be always used as Input to avoid 
problems with other hardware which does not expect data to be output 
there.<BR><BR><B>4000128h - SIOCNT - SIO Control, not used in GENERAL-PURPOSE 
Mode</B><BR>This register is not used in general purpose mode. That is, the 
separate bits of SIOCNT still exist and are read- and/or write-able in the same 
manner as for Normal, Multiplay, or UART mode (depending on SIOCNT Bit 12,13), 
but are having no effect on data being output to the link port.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=siocontrolregisterssummary></A><FONT size=+2>&nbsp;SIO Control 
      Registers Summary</FONT></TD></TR></TBODY></TABLE><BR><B>Mode Selection (by 
RCNT.15-14 and SIOCNT.13-12)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R.15 R.14 S.13 S.12 Mode
  0    x    0    0    Normal 8bit
  0    x    0    1    Normal 32bit
  0    x    1    0    Multiplay 16bit
  0    x    1    1    UART (RS232)
  1    0    x    x    General Purpose
  1    1    x    x    JOY BUS
</PRE></TD></TR></TBODY></TABLE><BR><B>SIOCNT</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    0      1    2     3      4 5 6   7     8    9      10   11
  Normal Master Rate SI/In SO/Out - - -   Start -    -      -    -
  Multi  Baud   Baud SI/In SD/In  ID# Err Start -    -      -    -
  UART   Baud   Baud CTS   Parity S R Err Bits  FIFO Parity Send Recv
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbainfraredcommunication></A><FONT size=+2>&nbsp;GBA Infrared 
      Communication</FONT></TD></TR></TBODY></TABLE><BR>Early GBA prototypes have been 
intended to include a built-in IR port for sending and receiving IR signals. 
Among others, this port could have been used to communicate with other GBAs, or 
older CGB models, or TV Remote Controls, etc.<BR><BR>[ THE INFRARED 
COMMUNICATION FEATURE IS -NOT- SUPPORTED ANYMORE ]<BR>Anyways, the prototype 
specifications have been as shown below...<BR><BR>Keep in mind that the IR 
signal may be interrupted by whatever objects moved between sender and receiver 
- the IR port isn't recommended for programs that require realtime data exchange 
(such like action games).<BR><BR><B>4000136h - IR - Infrared Register 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Transmission Data  (0=LED Off, 1=LED On)
  1     READ Enable        (0=Disable, 1=Enable)
  2     Reception Data     (0=None, 1=Signal received) (Read only)
  3     AMP Operation      (0=Off, 1=On)
  4     IRQ Enable Flag    (0=Disable, 1=Enable)
  5-15  Not used
</PRE></TD></TR></TBODY></TABLE>When IRQ is enabled, an interrupt is requested 
if the incoming signal was 0.119us Off (2 cycles), followed by 0.536us On (9 
cycles) - minimum timing periods each.<BR><BR><B>Transmission Notes</B><BR>When 
transmitting an IR signal, note that it'd be not a good idea to keep the LED 
turned On for a very long period (such like sending a 1 second synchronization 
pulse). The recipient's circuit would treat such a long signal as "normal IR 
pollution which is in the air" after a while, and thus ignore the 
signal.<BR><BR><B>Reception Notes</B><BR>Received data is internally latched. 
Latched data may be read out by setting both READ and AMP bits.<BR>Note: 
Provided that you don't want to receive your own IR signal, be sure to set Bit 0 
to zero before attempting to receive 
data.<BR><BR><B>Power-consumption</B><BR>After using the IR port, be sure to 
reset the register to zero in order to reduce battery power 
consumption.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbakeypadinput></A><FONT size=+2>&nbsp;GBA Keypad 
    Input</FONT></TD></TR></TBODY></TABLE><BR>The built-in GBA gamepad has 4 
direction keys, and 6 buttons.<BR><BR><B>4000130h - KEYINPUT - Key Status 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Button A        (0=Pressed, 1=Released)
  1     Button B        (etc.)
  2     Select          (etc.)
  3     Start           (etc.)
  4     Right           (etc.)
  5     Left            (etc.)
  6     Up              (etc.)
  7     Down            (etc.)
  8     Button R        (etc.)
  9     Button L        (etc.)
  10-15 Not used
</PRE></TD></TR></TBODY></TABLE>It'd be usually recommended to read-out this 
register only once per frame, and to store the current state in memory. As a 
side effect, this method avoids problems caused by switch bounce when a key is 
newly released or pressed.<BR><BR><B>4000132h - KEYCNT - Key Interrupt Control 
(R/W)</B><BR>The keypad IRQ function is intended to terminate the very-low-power 
Stop mode, it is not suitable for processing normal user input, to do this, most 
programs are invoking their keypad handlers from within VBlank IRQ.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Button A        (0=Ignore, 1=Select)
  1     Button B        (etc.)
  2     Select          (etc.)
  3     Start           (etc.)
  4     Right           (etc.)
  5     Left            (etc.)
  6     Up              (etc.)
  7     Down            (etc.)
  8     Button R        (etc.)
  9     Button L        (etc.)
  10-13 Not used
  14    IRQ Enable Flag (0=Disable, 1=Enable)
  15    IRQ Condition   (0=Logical OR, 1=Logical AND)
</PRE></TD></TR></TBODY></TABLE>In logical OR mode, an interrupt is requested 
when at least one of the selected buttons is pressed.<BR>In logical AND mode, an 
interrupt is requested when ALL of the selected buttons are 
pressed.<BR><BR><B>Notes</B><BR>In 8bit gameboy compatibility mode, L and R 
Buttons are used to toggle the screen size between normal 160x144 pixels and 
stretched 240x144 pixels.<BR>The GBA SP is additionally having a * Button used 
to toggle the backlight on and off (controlled by separate hardware logic, 
there's no way to detect or change the current backlight state by 
software).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbainterruptcontrol></A><FONT size=+2>&nbsp;GBA Interrupt 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000208h - IME - Interrupt Master 
Enable Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Disable all interrupts         (0=Disable All, 1=See IE register)
  1-15  Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000200h - IE - Interrupt Enable Register 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     LCD V-Blank                    (0=Disable)
  1     LCD H-Blank                    (etc.)
  2     LCD V-Counter Match            (etc.)
  3     Timer 0 Overflow               (etc.)
  4     Timer 1 Overflow               (etc.)
  5     Timer 2 Overflow               (etc.)
  6     Timer 3 Overflow               (etc.)
  7     Serial Communication           (etc.)
  8     DMA 0                          (etc.)
  9     DMA 1                          (etc.)
  10    DMA 2                          (etc.)
  11    DMA 3                          (etc.)
  12    Keypad                         (etc.)
  13    Game Pak (external IRQ source) (etc.)
  14-15 Not used
</PRE></TD></TR></TBODY></TABLE>Note that there is another 'master enable flag' 
directly in the CPUs Status Register (CPSR) accessible in privileged modes, see 
CPU reference for details.<BR><BR><B>4000202h - IF - Interrupt Request Flags / 
IRQ Acknowledge (R/W, see below)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     LCD V-Blank                    (1=Request Interrupt)
  1     LCD H-Blank                    (etc.)
  2     LCD V-Counter Match            (etc.)
  3     Timer 0 Overflow               (etc.)
  4     Timer 1 Overflow               (etc.)
  5     Timer 2 Overflow               (etc.)
  6     Timer 3 Overflow               (etc.)
  7     Serial Communication           (etc.)
  8     DMA 0                          (etc.)
  9     DMA 1                          (etc.)
  10    DMA 2                          (etc.)
  11    DMA 3                          (etc.)
  12    Keypad                         (etc.)
  13    Game Pak (external IRQ source) (etc.)
  14-15 Not used
</PRE></TD></TR></TBODY></TABLE>Interrupts must be manually acknowledged by 
writing a "1" to one of the IRQ bits, the IRQ bit will then be 
cleared.<BR><BR>"[Cautions regarding clearing IME and IE]<BR>A corresponding 
interrupt could occur even while a command to clear IME or each flag of the IE 
register is being executed. When clearing a flag of IE, you need to clear IME in 
advance so that mismatching of interrupt checks will not occur." ?<BR><BR>"[When 
multiple interrupts are used]<BR>When the timing of clearing of IME and the 
timing of an interrupt agree, multiple interrupts will not occur during that 
interrupt. Therefore, set (enable) IME after saving IME during the interrupt 
routine." ?<BR><BR><B>BIOS Interrupt handling</B><BR>Upon interrupt execution, 
the CPU is switched into IRQ mode, and the physical interrupt vector is called - 
as this address is located in BIOS ROM, the BIOS will always execute the 
following code before it forwards control to the user handler:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000018  b      128h                ;IRQ vector: jump to actual BIOS handler
  00000128  stmfd  r13!,r0-r3,r12,r14  ;save registers to SP_irq
  0000012C  mov    r0,4000000h         ;ptr+4 to 03FFFFFC (mirror of 03007FFC)
  00000130  add    r14,r15,0h          ;retadr for USER handler $+8=138h
  00000134  ldr    r15,[r0,-4h]        ;jump to [03FFFFFC] USER handler
  00000138  ldmfd  r13!,r0-r3,r12,r14  ;restore registers from SP_irq
  0000013C  subs   r15,r14,4h          ;return from IRQ (PC=LR-4, CPSR=SPSR)
</PRE></TD></TR></TBODY></TABLE>As shown above, a pointer to the 32bit/ARM-code 
user handler must be setup in [03007FFCh]. By default, 160 bytes of memory are 
reserved for interrupt stack at 03007F00h-03007F9Fh.<BR><BR><B>Recommended User 
Interrupt handling</B><BR>- If necessary switch to THUMB state manually (handler 
is called in ARM state)<BR>- Determine reason(s) of interrupt by examining IF 
register<BR>- User program may freely assign priority to each reason by own 
logic<BR>- Process the most important reason of your choice<BR>- User MUST 
manually acknowledge by writing to IF register<BR>- If user wants to allow 
nested interrupts, save SPSR_irq, then enable IRQs.<BR>- If using other 
registers than BIOS-pushed R0-R3, manually save R4-R11 also.<BR>- Note that 
Interrupt Stack is used (which may have limited size)<BR>- So, for memory 
consuming stack operations use system mode (=user stack).<BR>- When calling 
subroutines in system mode, save LSR_usr also.<BR>- Restore SPSR_irq and/or 
R4-R11 if you've saved them above.<BR>- Finally, return to BIOS handler by BX LR 
(R14_irq) instruction.<BR><BR><B>Default memory usage at 03007FXX (and mirrored 
to 03FFFFXX)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr. Size Expl.
  7FFCh 4    Pointer to user IRQ handler (32bit ARM code)
  7FF8h 4    Interrupt Check Flag (for IntrWait/VBlankIntrWait functions)
  7FF4h 4    Allocated Area
  7FF0h 4    Pointer to Sound Buffer
  7FE0h 16   Allocated Area
  7FA0h 64   Default area for SP_svc Supervisor Stack (4 words/time)
  7F00h 160  Default area for SP_irq Interrupt Stack (6 words/time)
</PRE></TD></TR></TBODY></TABLE>Memory below 7F00h is free for User Stack and 
user data. The three stack pointers are initially initialized at the TOP of the 
respective areas:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  SP_svc=03007FE0h
  SP_irq=03007FA0h
  SP_usr=03007F00h
</PRE></TD></TR></TBODY></TABLE>The user may redefine these addresses and move 
stacks into other locations, however, the addresses for system data at 
7FE0h-7FFFh are fixed.<BR><BR><B>Not sure, is following free for user 
?</B><BR>Registers R8-R12_fiq, R13_fiq, R14_fiq, SPSR_fiq<BR>Registers 
R13-R14_abt, SPSR_abt<BR>Registers R13-R14_und, SPSR_und<BR><BR><B>Fast 
Interrupt (FIQ)</B><BR>The ARM CPU provides two interrupt sources, IRQ and FIQ. 
In the GBA only IRQ is used. In normal GBAs, the FIQ signal is shortcut to 
VDD35, ie. the signal is always high, and there is no way to generate a FIQ by 
hardware. The registers R8..12_fiq could be used by software (when switching 
into FIQ mode by writing to CPSR) - however, this might make the game 
incompatible with hardware debuggers (which are reportedly using FIQs for 
debugging purposes).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbasystemcontrol></A><FONT size=+2>&nbsp;GBA System 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000204h - WAITCNT - Waitstate 
Control (R/W)</B><BR>This register is used to configure game pak access timings. 
The game pak ROM is mirrored to three address regions at 08000000h, 0A000000h, 
and 0C000000h, these areas are called Wait State 0-2. Different access timings 
may be assigned to each area (this might be useful in case that a game pak 
contains several ROM chips with different access times each).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-1   SRAM Wait Control          (0..3 = 4,3,2,8 cycles)
  2-3   Wait State 0 First Access  (0..3 = 4,3,2,8 cycles)
  4     Wait State 0 Second Access (0..1 = 2,1 cycles)
  5-6   Wait State 1 First Access  (0..3 = 4,3,2,8 cycles)
  7     Wait State 1 Second Access (0..1 = 4,1 cycles; unlike above WS0)
  8-9   Wait State 2 First Access  (0..3 = 4,3,2,8 cycles)
  10    Wait State 2 Second Access (0..1 = 8,1 cycles; unlike above WS0,WS1)
  11-12 PHI Terminal Output        (0..3 = Disable, 4.19MHz, 8.38MHz, 16.78MHz)
  13    Not used
  14    Game Pak Prefetch Buffer (Pipe) (0=Disable, 1=Enable)
  15    Game Pak Type Flag  (Read Only) (0=GBA, 1=CGB) (IN35 signal)
</PRE></TD></TR></TBODY></TABLE>At startup, the default setting is 0000h. 
Currently manufactured cartridges are using the following settings: WS0/ROM=3,1 
clks; SRAM=8 clks; WS2/EEPROM: 8,8 clks; prefetch enabled; that is, 
WAITCNT=4317h, for more info see "GBA Cartridges" chapter.<BR><BR>First Access 
(Non-sequential) and Second Access (Sequential) define the waitstates for N and 
S cycles, the actual access time is 1 clock cycle PLUS the number of 
waitstates.<BR>GamePak uses 16bit data bus, so that a 32bit access is split into 
TWO 16bit accesses (of which, the second fragment is always sequential, even if 
the first fragment was non-sequential).<BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gamepakprefetch">GamePak 
Prefetch</A><BR><BR>NOTES:<BR>The GBA forcefully uses non-sequential timing at 
the beginning of each 128K-block of gamepak ROM, eg. "LDMIA [801fff8h],r0-r7" 
will have non-sequential timing at 8020000h.<BR>The PHI Terminal output (PHI Pin 
of Gamepak Bus) should be disabled.<BR><BR><B>4000300h - POSTFLG - BYTE - 
Undocumented - Post Boot / Debug Control (R/W)</B><BR>After initial reset, the 
GBA BIOS initializes the register to 01h, and any further execution of the Reset 
vector (00000000h) will pass control to the Debug vector (0000001Ch) when 
sensing the register to be still set to 01h.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Undocumented. First Boot Flag  (0=First, 1=Further)
  1-7   Undocumented. Not used.
</PRE></TD></TR></TBODY></TABLE>Normally the debug handler rejects control 
unless it detects Debug flags in cartridge header, in that case it may redirect 
to a cut-down boot procedure (bypassing Nintendo logo and boot delays, much like 
nocash burst boot for multiboot software). I am not sure if it is possible to 
reset the GBA externally without automatically resetting register 300h 
though.<BR><BR><B>4000301h - HALTCNT - BYTE - Undocumented - Low Power Mode 
Control (W)</B><BR>Writing to this register switches the GBA into battery saving 
mode.<BR>In Halt mode, the CPU is paused as long as (IE AND IF)=0, this should 
be used to reduce power-consumption during periods when the CPU is waiting for 
interrupt events.<BR>In Stop mode, most of the hardware including sound and 
video are paused, this very-low-power mode could be used much like a 
screensaver.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-6   Undocumented. Not used.
  7     Undocumented. Power Down Mode  (0=Halt, 1=Stop)
</PRE></TD></TR></TBODY></TABLE>The current GBA BIOS addresses only the upper 
eight bits of this register (by writing 00h or 80h to address 04000301h), 
however, as the register isn't officially documented, some or all of the bits 
might have different meanings in future GBA models.<BR>For best forwards 
compatibility, it'd generally be more recommended to use the BIOS Functions SWI 
2 (Halt) or SWI 3 (Stop) rather than writing to this register 
directly.<BR><BR><B>4000410h - Undocumented - Purpose Unknown ? 8bit 
(W)</B><BR>The BIOS writes the 8bit value 0FFh to this address. Purpose 
Unknown.<BR>Probably just another bug in the BIOS.<BR><BR><B>4000800h - 32bit - 
Undocumented - Internal Memory Control (R/W)</B><BR>Supported by GBA and GBA SP 
only - NOT supported by DS (even in GBA mode).<BR>Initialized to 0D000020h (by 
hardware). Unlike all other I/O registers, this register is mirrored across the 
whole I/O area (in increments of 64K, ie. at 4000800h, 4010800h, 4020800h, ..., 
4FF0800h)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Disable 32K+256K WRAM (0=Normal, 1=Disable) (when off: empty/prefetch)
  1-3   Unknown          (Read/Write-able)
  4     Unknown          (Always zero, not used or write only)
  5     Enable 256K WRAM (0=Disable, 1=Normal) (when off: mirror of 32K WRAM)
  6-23  Unknown          (Always zero, not used or write only)
  24-27 Wait Control WRAM 256K (0-14 = 15..1 Waitstates, 15=Lockup)
  28-31 Unknown          (Read/Write-able)
</PRE></TD></TR></TBODY></TABLE>The value 0Dh in Bits 24-27 selects 2 waitstates 
for 256K WRAM (ie. 3/3/6 cycles 8/16/32bit accesses). The fastest possible 
setting would be 0Eh (1 waitstate, 2/2/4 cycles for 8/16/32bit).<BR><BR>Note: 
One cycle equals approx. 59.59ns (ie. 16.78MHz clock).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gamepakprefetch></A><FONT size=+2>&nbsp;GamePak 
    Prefetch</FONT></TD></TR></TBODY></TABLE><BR>GamePak Prefetch can be enabled in 
WAITCNT register. When prefetch buffer is enabled, the GBA attempts to read 
opcodes from Game Pak ROM during periods when the CPU is not using the bus (if 
any). Memory access is then performed with 0 Waits if the CPU requests data 
which is already stored in the buffer. The prefetch buffer stores up to eight 
16bit values.<BR><BR><B>GamePak ROM Opcodes</B><BR>The prefetch feature works 
only with &lt;opcodes&gt; fetched from GamePak ROM. Opcodes executed in RAM or 
BIOS are not affected by the prefetch feature (even if that opcodes read 
&lt;data&gt; from GamePak ROM).<BR><BR><B>Prefetch Enable</B><BR>For GamePak ROM 
opcodes, prefetch may occur in two situations:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1) opcodes with internal cycles (I) which do not change R15, shift/rotate
     register-by-register, load opcodes (ldr,ldm,pop,swp), multiply opcodes
  2) opcodes that load/store memory (ldr,str,ldm,stm,etc.)
</PRE></TD></TR></TBODY></TABLE><BR><B>Prefetch Disable Bug</B><BR>When Prefetch 
is disabled, the Prefetch Disable Bug will occur for all<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  "Opcodes in GamePak ROM with Internal Cycles which do not change R15"
</PRE></TD></TR></TBODY></TABLE>for those opcodes, the bug changes the opcode 
fetch time from 1S to 1N.<BR>Note: Affected opcodes (with I cycles) are: 
Shift/rotate register-by-register opcodes, multiply opcodes, and load opcodes 
(ldr,ldm,pop,swp).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartridges></A><FONT size=+2>&nbsp;GBA 
  Cartridges</FONT></TD></TR></TBODY></TABLE><BR><B>ROM</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartridgeheader">GBA Cartridge 
Header</A><BR><A href="http://nocash.emubase.de/gbatek.htm#gbacartridgerom">GBA 
Cartridge ROM</A><BR><BR><B>Backup Media</B><BR>Aside from ROM, cartridges may 
also include one of the following backup medias, used to store game positions, 
highscore tables, options, or other data.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartbackupids">GBA Cart Backup 
IDs</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartbackupsramfram">GBA Cart Backup 
SRAM/FRAM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartbackupeeprom">GBA Cart Backup 
EEPROM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartbackupflashrom">GBA Cart Backup 
Flash ROM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartbackupdacs">GBA Cart Backup 
DACS</A><BR><BR><B>Add-Ons</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartioportgpio">GBA Cart I/O Port 
(GPIO)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartrealtimeclockrtc">GBA Cart 
Real-Time Clock (RTC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartsolarsensor">GBA Cart Solar 
Sensor</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacarttiltsensor">GBA Cart Tilt 
Sensor</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartgyrosensor">GBA Cart Gyro 
Sensor</A><BR><A href="http://nocash.emubase.de/gbatek.htm#gbacartrumble">GBA 
Cart Rumble</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereader">GBA Cart 
e-Reader</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartunknowndevices">GBA Cart 
Unknown Devices</A><BR><BR><B>Other Accessoires</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbaflashcards">GBA 
Flashcards</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacheatdevices">GBA Cheat 
Devices</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartridgeheader></A><FONT size=+2>&nbsp;GBA Cartridge 
      Header</FONT></TD></TR></TBODY></TABLE><BR>The first 192 bytes at 
8000000h-80000BFh in ROM are used as cartridge header. The same header is also 
used for Multiboot images at 2000000h-20000BFh (plus some additional multiboot 
entries at 20000C0h and up).<BR><BR><B>Header Overview</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Address Bytes Expl.
  000h    4     ROM Entry Point  (32bit ARM branch opcode, eg. "B rom_start")
  004h    156   Nintendo Logo    (compressed bitmap, required!)
  0A0h    12    Game Title       (uppercase ascii, max 12 characters)
  0ACh    4     Game Code        (uppercase ascii, 4 characters)
  0B0h    2     Maker Code       (uppercase ascii, 2 characters)
  0B2h    1     Fixed value      (must be 96h, required!)
  0B3h    1     Main unit code   (00h for current GBA models)
  0B4h    1     Device type      (usually 00h)
  0B5h    7     Reserved Area    (should be zero filled)
  0BCh    1     Software version (usually 00h)
  0BDh    1     Complement check (header checksum, required!)
  0BEh    2     Reserved Area    (should be zero filled)
  --- Additional Multiboot Header Entries ---
  0C0h    4     RAM Entry Point  (32bit ARM branch opcode, eg. "B ram_start")
  0C4h    1     Boot mode        (init as 00h - BIOS overwrites this value!)
  0C5h    1     Slave ID Number  (init as 00h - BIOS overwrites this value!)
  0C6h    26    Not used         (seems to be unused)
  0E0h    4     JOYBUS Entry Pt. (32bit ARM branch opcode, eg. "B joy_start")
</PRE></TD></TR></TBODY></TABLE>Note: With all entry points, the CPU is 
initially set into system mode.<BR><BR><B>000h - Entry Point, 4 
Bytes</B><BR>Space for a single 32bit ARM opcode that redirects to the actual 
startaddress of the cartridge, this should be usually a "B &lt;start&gt;" 
instruction.<BR>Note: This entry is ignored by Multiboot slave GBAs (in fact, 
the entry is then overwritten and redirected to a separate Multiboot Entry 
Point, as described below).<BR><BR><B>004h..09Fh - Nintendo Logo, 156 
Bytes</B><BR>Contains the Nintendo logo which is displayed during the boot 
procedure. Cartridge won't work if this data is missing or modified.<BR>In 
detail: This area contains Huffman compression data (but excluding the 
compression header which is hardcoded in the BIOS, so that it'd be probably not 
possible to hack the GBA by producing de-compression buffer overflows).<BR>A 
copy of the compression data is stored in the BIOS, the GBA will compare this 
data and lock-up itself if the BIOS data isn't exactly the same as in the 
cartridge (or multiboot header). The only exception are the two entries below 
which are allowed to have variable settings in some bits.<BR><BR><B>09Ch Bit 2,7 
- Debugging Enable</B><BR>This is part of the above Nintendo Logo area, and must 
be commonly set to 21h, however, Bit 2 and Bit 7 may be set to other 
values.<BR>When both bits are set (ie. A5h), the FIQ/Undefined Instruction 
handler in the BIOS becomes unlocked, the handler then forwards these exceptions 
to the user handler in cartridge ROM (entry point defined in 80000B4h, see 
below).<BR>Other bit combinations currently do not seem to have special 
functions.<BR><BR><B>09Eh Bit 0,1 - Cartridge Key Number MSBs</B><BR>This is 
part of the above Nintendo Logo area, and must be commonly set to F8h, however, 
Bit 0-1 may be set to other values.<BR>During startup, the BIOS performs some 
dummy-reads from a stream of pre-defined addresses, even though these reads seem 
to be meaningless, they might be intended to unlock a read-protection inside of 
commercial cartridge. There are 16 pre-defined address streams - selected by a 
4bit key number - of which the upper two bits are gained from 800009Eh Bit 0-1, 
and the lower two bits from a checksum across header bytes 09Dh..0B7h (bytewise 
XORed, divided by 40h).<BR><BR><B>0A0h - Game Title, Uppercase Ascii, max 12 
characters</B><BR>Space for the game title, padded with 00h (if less than 12 
chars).<BR><BR><B>0ACh - Game Code, Uppercase Ascii, 4 characters</B><BR>This is 
the same code as the AGB-UTTD code which is printed on the package and sticker 
on (commercial) cartridges (excluding the leading "AGB-" part).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  U  Unique Code          (usually "A" or "B" or special meaning)
  TT Short Title          (eg. "PM" for Pac Man)
  D  Destination/Language (usually "J" or "E" or "P" or specific language)
</PRE></TD></TR></TBODY></TABLE>The first character (U) is usually "A" or "B", 
in detail:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  A  Normal game; Older titles (mainly 2001..2003)
  B  Normal game; Newer titles (2003..)
  C  Normal game; Not used yet, but might be used for even newer titles
  F  Classic NES Series (software emulated NES games)
  K  Yoshi and Koro Koro Puzzle (acceleration sensor)
  P  e-Reader (dot-code scanner)
  R  Warioware Twisted (cartridge with rumble and z-axis gyro sensor)
  U  Boktai 1 and 2 (cartridge with RTC and solar sensor)
  V  Drill Dozer (cartridge with rumble)
</PRE></TD></TR></TBODY></TABLE>The second/third characters (TT) are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Usually an abbreviation of the game title (eg. "PM" for "Pac Man") (unless
  that gamecode was already used for another game, then TT is just random)
</PRE></TD></TR></TBODY></TABLE>The fourth character (D) indicates 
Destination/Language:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  J  Japan             P  Europe/Elsewhere   F  French          S  Spanish
  E  USA/English       D  German             I  Italian
</PRE></TD></TR></TBODY></TABLE><BR><B>0B0h - Maker code, Uppercase Ascii, 2 
characters</B><BR>Identifies the (commercial) developer. For example, 
"01"=Nintendo.<BR><BR><B>0B2h - Fixed value, 1 Byte</B><BR>Must be 
96h.<BR><BR><B>0B3h - Main unit code, 1 Byte</B><BR>Identifies the required 
hardware. Should be 00h for current GBA models.<BR><BR><B>0B4h - Device type, 1 
Byte</B><BR>Normally, this entry should be zero. With Nintendo's hardware 
debugger Bit 7 identifies the debugging handlers entry point and size of DACS 
(Debugging And Communication System) memory: Bit7=0: 9FFC000h/8MBIT DACS, 
Bit7=1: 9FE2000h/1MBIT DACS. The debugging handler can be enabled in 800009Ch 
(see above), normal cartridges do not have any memory (nor any mirrors) at these 
addresses though.<BR><BR><B>0B5h - Reserved Area, 7 Bytes</B><BR>Reserved, zero 
filled.<BR><BR><B>0BCh - Software version number</B><BR>Version number of the 
game. Usually zero.<BR><BR><B>0BDh - Complement check, 1 Byte</B><BR>Header 
checksum, cartridge won't work if incorrect. Calculate as such:<BR>chk=0:for 
i=0A0h to 0BCh:chk=chk-[i]:next:chk=(chk-19h) and 0FFh<BR><BR><B>0BEh - Reserved 
Area, 2 Bytes</B><BR>Reserved, zero filled.<BR><BR>Below required for 
Multiboot/slave programs only. For Multiboot, the above 192 bytes are required 
to be transferred as header-block (loaded to 2000000h-20000BFh), and some 
additional header-information must be located at the beginning of the actual 
program/data-block (loaded to 20000C0h and up). This extended header consists of 
Multiboot Entry point(s) which must be set up correctly, and of two reserved 
bytes which are overwritten by the boot procedure:<BR><BR><B>0C0h - 
Normal/Multiplay mode Entry Point</B><BR>This entry is used only if the GBA has 
been booted by using Normal or Multiplay transfer mode (but not by Joybus 
mode).<BR>Typically deposit a ARM-32bit "B &lt;start&gt;" branch opcode at this 
location, which is pointing to your actual initialization 
procedure.<BR><BR><B>0C4h (BYTE) - Boot mode</B><BR>The slave GBA download 
procedure overwrites this byte by a value which is indicating the used multiboot 
transfer mode.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Value  Expl.
  01h    Joybus mode
  02h    Normal mode
  03h    Multiplay mode
</PRE></TD></TR></TBODY></TABLE>Typically set this byte to zero by inserting DCB 
00h in your source.<BR>Be sure that your uploaded program does not contain 
important program code or data at this location, or at the ID-byte location 
below.<BR><BR><B>0C5h (BYTE) - Slave ID Number</B><BR>If the GBA has been booted 
in Normal or Multiplay mode, this byte becomes overwritten by the slave ID 
number of the local GBA (that'd be always 01h for normal mode).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Value  Expl.
  01h    Slave #1
  02h    Slave #2
  03h    Slave #3
</PRE></TD></TR></TBODY></TABLE>Typically set this byte to zero by inserting DCB 
00h in your source.<BR>When booted in Joybus mode, the value is NOT changed and 
remains the same as uploaded from the master GBA.<BR><BR><B>0C6h..0DFh - Not 
used</B><BR>Appears to be unused.<BR><BR><B>0E0h - Joybus mode Entry 
Point</B><BR>If the GBA has been booted by using Joybus transfer mode, then the 
entry point is located at this address rather than at 20000C0h. Either put your 
initialization procedure directly at this address, or redirect to the actual 
boot procedure by depositing a "B &lt;start&gt;" opcode here (either one using 
32bit ARM code). Or, if you are not intending to support joybus mode (which is 
probably rarely used), ignore this entry.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartridgerom></A><FONT size=+2>&nbsp;GBA Cartridge 
      ROM</FONT></TD></TR></TBODY></TABLE><BR><B>ROM Size</B><BR>The games F-ZERO and 
Super Mario Advance use ROMs of 4 MBytes each. Zelda uses 8 MBytes. Not sure if 
other sizes are manufactured.<BR><BR><B>ROM Waitstates</B><BR>The GBA starts the 
cartridge with 4,2 waitstates (N,S) and prefetch disabled. The program may 
change these settings by writing to WAITCNT, the games F-ZERO and Super Mario 
Advance use 3,1 waitstates (N,S) each, with prefetch enabled.<BR>Third-party 
flashcards are reportedly running unstable with these settings. Also, prefetch 
and shorter waitstates are allowing to read more data and opcodes from ROM is 
less time, the downside is that it increases the power 
consumption.<BR><BR><B>ROM Chip</B><BR>Because of how 24bit addresses are 
squeezed through the Gampak bus, the cartridge must include a circuit that 
latches the lower 16 address bits on non-sequential access, and that increments 
these bits on sequential access. Nintendo includes this circuit directly in the 
ROM chip.<BR>Also, the ROM must have 16bit data bus (or a circuit which converts 
two 8bit data units into one 16bit unit - by not exceeding the waitstate 
timings).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartbackupids></A><FONT size=+2>&nbsp;GBA Cart Backup 
      IDs</FONT></TD></TR></TBODY></TABLE><BR>Nintendo didn't include a backup-type 
entry in the ROM header, however, the required type can be detected by ID 
strings in the ROM-image. Nintendo's tools are automatically inserting these 
strings (as part of their library headers). When using other tools, you may 
insert ID strings by hand.<BR><BR><B>ID Strings</B><BR>The ID string must be 
located at a word-aligned memory location, the string length should be a 
multiple of 4 bytes (padded with zero's).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  EEPROM_Vnnn    EEPROM 512 bytes or 8 Kbytes (4Kbit or 64Kbit)
  SRAM_Vnnn      SRAM 32 Kbytes (256Kbit)
  FLASH_Vnnn     FLASH 64 Kbytes (512Kbit) (ID used in older files)
  FLASH512_Vnnn  FLASH 64 Kbytes (512Kbit) (ID used in newer files)
  FLASH1M_Vnnn   FLASH 128 Kbytes (1Mbit)
</PRE></TD></TR></TBODY></TABLE>For Nintendo's tools, "nnn" is a 3-digit library 
version number. When using other tools, best keep it set to "nnn" rather than 
inserting numeric digits.<BR><BR><B>Notes</B><BR>No$gba does auto-detect most 
backup types, even without ID strings, except for 128K FLASH (without ID 
"FLASH1M_Vnnn", the FLASH size defaults to 64K). Ideally, for faster detection, 
the ID should be put into the first some bytes of the ROM-image (ie. somewhere 
right after the ROM header).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartbackupsramfram></A><FONT size=+2>&nbsp;GBA Cart Backup 
      SRAM/FRAM</FONT></TD></TR></TBODY></TABLE><BR>SRAM - 32 KBytes (256Kbit) 
Lifetime: Depends on back-up battery<BR>FRAM - 32 KBytes (256Kbit) Lifetime: 
10,000,000,000 read/write per bit<BR><BR>Hyundai GM76V256CLLFW10 SRAM (Static 
RAM) (eg. F-Zero)<BR>Fujitsu MB85R256 FRAM (Ferroelectric RAM) (eg. Warioware 
Twisted)<BR><BR><B>Addressing and Waitstates</B><BR>SRAM/FRAM is mapped to 
E000000h-E007FFFh, it should be accessed with 8 waitstates (write a value of 3 
into Bit0-1 of WAITCNT).<BR><BR><B>Databus Width</B><BR>The SRAM/FRAM databus is 
restricted to 8 bits, it should be accessed by LDRB, LDRSB, and STRB opcodes 
only.<BR><BR><B>Reading and Writing</B><BR>Reading from SRAM/FRAM should be 
performed by code executed in WRAM only (but not by code executed in ROM). There 
is no such restriction for writing.<BR><BR><B>Preventing Data Loss</B><BR>The 
GBA SRAM/FRAM carts do not include a write-protect function (unlike older 8bit 
gameboy carts). This seems to be a problem and may cause data loss when a 
cartridge is removed or inserted while the GBA is still turned on. As far as I 
understand, this is not so much a hardware problem, but rather a software 
problem, ie. theoretically you could remove/insert the cartridge as many times 
as you want, but you should take care that your program does not crash (and 
write blindly into memory).<BR><BR><B>Recommended Workaround</B><BR>Enable the 
Gamepak Interrupt (it'll most likely get triggered when removing the cartridge), 
and hang-up the GBA in an endless loop when your interrupt handler senses a 
Gamepak IRQ. For obvious reason, your interrupt handler should be located in 
WRAM, ie. not in the (removed) ROM cartridge. The handler should process Gamepak 
IRQs at highest priority. Periods during which interrupts are disabled should be 
kept as short as possible, if necessary allow nested interrupts.<BR><BR><B>When 
to use the above Workaround</B><BR>A program that relies wholly on code and data 
in WRAM, and that does not crash even when ROM is removed, may keep operating 
without having to use the above mechanism.<BR>Do NOT use the workaround for 
programs that run without a cartridge inserted (ie. single gamepak/multiboot 
slaves), or for programs that use Gamepak IRQ/DMA for other purposes.<BR>All 
other programs should use it. It'd be eventually a good idea to include it even 
in programs that do not use SRAM/FRAM themselves (eg. otherwise removing a 
SRAM/FRAM-less cartridge may lock up the GBA, and may cause it to destroy backup 
data when inserting a SRAM/FRAM cartridge).<BR><BR><B>SRAM vs FRAM</B><BR>FRAM 
(Ferroelectric RAM) is a newer technology, used in newer GBA carts, unlike SRAM 
(Static RAM), it doesn't require a battery to hold the data. At software side, 
it is accessed exactly like SRAM, ie. unlike EEPROM/FLASH, it doesn't require 
any Write/Erase commands/delays.<BR><BR><B>Note</B><BR>In SRAM/FRAM cartridges, 
the /REQ pin (Pin 31 of Gamepak bus) should be a little bit shorter as than the 
other pins; when removing the cartridge, this causes the gamepak IRQ signal to 
get triggered before the other pins are disconnected.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartbackupeeprom></A><FONT size=+2>&nbsp;GBA Cart Backup 
      EEPROM</FONT></TD></TR></TBODY></TABLE><BR>9853 - EEPROM 512 Bytes (0200h) 
(4Kbit) (eg. used by Super Mario Advance)<BR>9854 - EEPROM 8 KBytes (2000h) 
(64Kbit) (eg. used by Boktai)<BR>Lifetime: 100,000 writes per 
address<BR><BR><B>Addressing and Waitstates</B><BR>The eeprom is connected to 
Bit0 of the data bus, and to the upper 1 bit (or upper 17 bits in case of large 
32MB ROM) of the cartridge ROM address bus, communication with the chip takes 
place serially.<BR>The eeprom must be used with 8 waitstates (set WAITCNT=X3XXh; 
8,8 clks in WS2 area), the eeprom can be then addressed at 
DFFFF00h..DFFFFFFh.<BR>Respectively, with eeprom, ROM is restricted to 
8000000h-9FFFeFFh (max. 1FFFF00h bytes = 32MB minus 256 bytes). On carts with 
16MB or smaller ROM, eeprom can be alternately accessed anywhere at 
D000000h-DFFFFFFh.<BR><BR><B>Data and Address Width</B><BR>Data can be read from 
(or written to) the EEPROM in units of 64bits (8 bytes). Writing automatically 
erases the old 64bits of data. Addressing works in units of 64bits respectively, 
that is, for 512 Bytes EEPROMS: an address range of 0-3Fh, 6bit bus width; and 
for 8KByte EEPROMs: a range of 0-3FFh, 14bit bus width (only the lower 10 
address bits are used, upper 4 bits should be zero).<BR><BR><B>Set Address (For 
Reading)</B><BR>Prepare the following bitstream in memory:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2 bits "11" (Read Request)
  n bits eeprom address (MSB first, 6 or 14 bits, depending on EEPROM)
  1 bit "0"
</PRE></TD></TR></TBODY></TABLE>Then transfer the stream to eeprom by using 
DMA.<BR><BR><B>Read Data</B><BR>Read a stream of 68 bits from EEPROM by using 
DMA,<BR>then decipher the received data as follows:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4 bits - ignore these
 64 bits - data (conventionally MSB first)
</PRE></TD></TR></TBODY></TABLE><BR><B>Write Data to Address</B><BR>Prepare the 
following bitstream in memory, then transfer the stream to eeprom by using DMA, 
it'll take ca. 108368 clock cycles (ca. 6.5ms) until the old data is erased and 
new data is programmed.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2 bits "10" (Write Request)
  n bits eeprom address (MSB first, 6 or 14 bits, depending on EEPROM)
 64 bits data (conventionally MSB first)
  1 bit "0"
</PRE></TD></TR></TBODY></TABLE>After the DMA, keep reading from the chip, by 
normal LDRH [DFFFF00h], until Bit 0 of the returned data becomes "1" (Ready). To 
prevent your program from locking up in case of malfunction, generate a timeout 
if the chip does not reply after 10ms or longer.<BR><BR><B>Using 
DMA</B><BR>Transferring a bitstream to/from the EEPROM by LDRH/STRH opcodes does 
not work, this might be because of timing problems, or because how the GBA 
squeezes non-sequential memory addresses through the external address/data 
bus.<BR>For this reason, a buffer in memory must be used (that buffer would be 
typically allocated temporarily on stack, one halfword for each bit, bit1-15 of 
the halfwords are don't care, only bit0 is of interest).<BR>The buffer must be 
transfered as a whole to/from EEPROM by using DMA3 (only DMA 3 is valid to read 
&amp; write external memory), use 16bit transfer mode, both source and 
destination address incrementing (ie. DMA3CNT=80000000h+length).<BR>DMA channels 
of higher priority should be disabled during the transfer (ie. H/V-Blank or 
Sound FIFO DMAs). And, of course any interrupts that might mess with DMA 
registers should be disabled.<BR><BR><B>Pin-Outs</B><BR>The EEPROM chips are 
having only 8 pins, these are connected, Pin 1..8, to ROMCS, RD, WR, AD0, GND, 
GND, A23, VDD of the GamePak bus. Carts with 32MB ROM must have A7..A22 
logically ANDed with A23.<BR><BR><B>Notes</B><BR>There seems to be no 
autodection mechanism, so that a hardcoded bus width must be used.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartbackupflashrom></A><FONT size=+2>&nbsp;GBA Cart Backup 
      Flash ROM</FONT></TD></TR></TBODY></TABLE><BR>64 KBytes - 512Kbits Flash ROM - 
Lifetime: 10,000 writes per sector<BR>128 KBytes - 1Mbit Flash ROM - Lifetime: 
??? writes per sector<BR><BR><B>Chip Identification (all device types)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=90h  (enter ID mode)
  dev=[E000001h], man=[E000000h]                  (get device &amp; manufacturer)
  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=F0h  (terminate ID mode)
</PRE></TD></TR></TBODY></TABLE>Used to detect the type (and presence) of FLASH 
chips. See Device Types below.<BR><BR><B>Reading Data Bytes (all device 
types)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  dat=[E00xxxxh]                                  (read byte from address xxxx)
</PRE></TD></TR></TBODY></TABLE><BR><B>Erase Entire Chip (all device 
types)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=80h  (erase command)
  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=10h  (erase entire chip)
  wait until [E000000h]=FFh (or timeout)
</PRE></TD></TR></TBODY></TABLE>Erases all memory in chip, erased memory is 
FFh-filled.<BR><BR><B>Erase 4Kbyte Sector (all device types, except 
Atmel)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=80h  (erase command)
  [E005555h]=AAh, [E002AAAh]=55h, [E00n000h]=30h  (erase sector n)
  wait until [E00n000h]=FFh (or timeout)
</PRE></TD></TR></TBODY></TABLE>Erases memory at E00n000h..E00nFFFh, erased 
memory is FFh-filled.<BR><BR><B>Erase-and-Write 128 Bytes Sector (only Atmel 
devices)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  old=IME, IME=0                                  (disable interrupts)
  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=A0h  (erase/write sector command)
  [E00xxxxh+00h..7Fh]=dat[00h..7Fh]               (write 128 bytes)
  IME=old                                         (restore old IME state)
  wait until [E00xxxxh+7Fh]=dat[7Fh] (or timeout)
</PRE></TD></TR></TBODY></TABLE>Interrupts (and DMAs) should be disabled during 
command/write phase. Target address must be a multiple of 80h.<BR><BR><B>Write 
Single Data Byte (all device types, except Atmel)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=A0h  (write byte command)
  [E00xxxxh]=dat                                  (write byte to address xxxx)
  wait until [E00xxxxh]=dat (or timeout)
</PRE></TD></TR></TBODY></TABLE>The target memory location must have been 
previously erased.<BR><BR><B>Terminate Command after Timeout (only Macronix 
devices, ID=1CC2h)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=F0h                            (force end of write/erase command)
</PRE></TD></TR></TBODY></TABLE>Use if timeout occurred during "wait until" 
periods, for Macronix devices only.<BR><BR><B>Bank Switching (devices bigger 
than 64K only)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [E005555h]=AAh, [E002AAAh]=55h, [E005555h]=B0h  (select bank command)
  [E000000h]=bnk                                  (write bank number 0..1)
</PRE></TD></TR></TBODY></TABLE>Specifies 64K bank number for read/write/erase 
operations.<BR>Required because gamepak flash/sram addressbus is limited to 
16bit width.<BR><BR><B>Device Types</B><BR>Nintendo puts different FLASH chips 
in commercial game cartridges. Developers should thus detect &amp; support all 
chip types. For Atmel chips it'd be recommended to simulate 4K sectors by 
software, though reportedly Nintendo doesn't use Atmel chips in newer games 
anymore. Also mind that different timings should not disturb compatibility and 
performance.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ID     Name       Size  Sectors  AverageTimings  Timeouts/ms   Waits
  D4BFh  SST        64K   16x4K    20us?,?,?       10,  40, 200  3,2
  1CC2h  Macronix   64K   16x4K    ?,?,?           10,2000,2000  8,3
  1B32h  Panasonic  64K   16x4K    ?,?,?           10, 500, 500  4,2
  3D1Fh  Atmel      64K   512x128  ?,?,?           ...40..,  40  8,8
  1362h  Sanyo      128K  ?        ?,?,?           ?    ?    ?    ?
  09C2h  Macronix   128K  ?        ?,?,?           ?    ?    ?    ?
</PRE></TD></TR></TBODY></TABLE>Identification Codes MSB=Device Type, 
LSB=Manufacturer.<BR>Size in bytes, and numbers of sectors * sector size in 
bytes.<BR>Average medium Write, Erase Sector, Erase Chips timings are 
unknown?<BR>Timeouts in milliseconds for Write, Erase Sector, Erase 
Chips.<BR>Waitstates for Writes, and Reads in clock cycles.<BR><BR><B>Accessing 
FLASH Memory</B><BR>FLASH memory is located in the "SRAM" area at 
E000000h..E00FFFFh, which is restricted to 16bit address and 8bit data 
buswidths. Respectively, the memory can be accessed &lt;only&gt; by 8bit 
read/write LDRB/STRB opcodes.<BR>Also, reading anything (data or status/busy 
information) can be done &lt;only&gt; by opcodes executed in WRAM (not from 
opcodes in ROM) (there's no such restriction for writing).<BR><BR><B>FLASH 
Waitstates</B><BR>Use 8 clk waitstates for initial detection (WAITCNT Bits 0,1 
both set). After detection of certain device types smaller wait values may be 
used for write/erase, and even smaller wait values for raw reading, see Device 
Types table.<BR>In practice, games seem to use smaller values only for 
write/erase (even though those operations are slow anyways), whilst raw reads 
are always done at 8 clk waits (even though reads could actually benefit 
slightly from smaller wait values).<BR><BR><B>Verify Write/Erase and 
Retry</B><BR>Even though device signalizes the completion of write/erase 
operations, it'd be recommended to read/confirm the content of the changed 
memory area by software. In practice, Nintendo's "erase-write-verify-retry" 
function typically repeats the operation up to three times in case of 
errors.<BR>Also, for SST devices only, the "erase-write" and 
"erase-write-verify-retry" functions repeat the erase command up to 80 times, 
additionally followed by one further erase command if no retries were needed, 
otherwise followed by six further erase commands.<BR><BR><B>Note</B><BR>FLASH 
(64Kbytes) is used by the game Sonic Advance, and possibly others.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartbackupdacs></A><FONT size=+2>&nbsp;GBA Cart Backup 
      DACS</FONT></TD></TR></TBODY></TABLE><BR>128 KBytes - 1Mbit DACS - Lifetime: 
100,000 writes.<BR>1024 KBytes - 8Mbit DACS - Lifetime: 100,000 
writes.<BR><BR>DACS (Debugging And Communication System) is used in Nintendo's 
hardware debugger only, DACS is NOT used in normal game cartridges.<BR><BR>Parts 
of DACS memory is used to store the debugging exception handlers (entry 
point/size defined in cartridge header), the remaining memory could be used to 
store game positions or other data. The address space is the upper end of the 
32MB ROM area, the memory can be read directly by the CPU, including for ability 
to execute program code in this area.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartioportgpio></A><FONT size=+2>&nbsp;GBA Cart I/O Port 
      (GPIO)</FONT></TD></TR></TBODY></TABLE><BR>4bit General Purpose I/O Port (GPIO) 
- contained in the ROM-chip<BR><BR>Used by Boktai for RTC and Solar 
Sensor:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartrealtimeclockrtc">GBA Cart 
Real-Time Clock (RTC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartsolarsensor">GBA Cart Solar 
Sensor</A><BR>And by Warioware Twisted for Rumble and Z-Axis Sensor:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartrumble">GBA Cart 
Rumble</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartgyrosensor">GBA Cart Gyro 
Sensor</A><BR>Might be also used by other games for other purposes, such like 
other sensors, or SRAM bank switching, etc.<BR><BR>The I/O registers are mapped 
to a 6-byte region in the ROM-area at 80000C4h, the 6-byte region should be 
zero-filled in the ROM-image. In Boktai, the size of the zero-filled region is 
0E0h bytes - that probably due to an incorrect definition (the additional bytes 
do not contain any extra ports, nor mirrors of the ports in the 6-byte region). 
Observe that ROM-bus writes are limited to 16bit/32bit access (STRB opocdes are 
ignored; that, only in DS mode?).<BR><BR><B>80000C4h - I/O Port Data (selectable 
W or R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  bit0-3  Data Bits 0..3 (0=Low, 1=High)
  bit4-15 not used (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>80000C6h - I/O Port Direction (for above 
Data Port) (selectable W or R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  bit0-3  Direction for Data Port Bits 0..3 (0=In, 1=Out)
  bit4-15 not used (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>80000C8h - I/O Port Control (selectable W 
or R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  bit0    Register 80000C4h..80000C8h Control (0=Write-Only, 1=Read/Write)
  bit1-15 not used (0)
</PRE></TD></TR></TBODY></TABLE>In write-only mode, reads return 00h (or 
possible other data, if the rom contains non-zero data at that 
location).<BR><BR><B>Connection Examples</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GPIO       | Boktai  | Wario
  Bit Pin    | RTC SOL | GYR RBL
  -----------+---------+---------
  0   ROM.1  | SCK CLK | RES -
  1   ROM.2  | SIO RST | CLK -
  2   ROM.21 | CS  -   | DTA -
  3   ROM.22 | -   FLG | -   MOT
  -----------+---------+---------
  IRQ ROM.43 | IRQ -   | -   -
</PRE></TD></TR></TBODY></TABLE><BR>Aside from the I/O Port, the ROM-chip also 
includes an inverter (used for inverting the RTC /IRQ signal), and some sort of 
an (unused) address decoder output (which appears to be equal or related to A23 
signal) (ie. reacting on ROM A23, or SRAM D7, which share the same pin on GBA 
slot).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartrealtimeclockrtc></A><FONT size=+2>&nbsp;GBA Cart 
      Real-Time Clock (RTC)</FONT></TD></TR></TBODY></TABLE><BR>S3511 - 8pin RTC with 
3-wire serial bus (used in Boktai)<BR><BR>The RTC chip is (almost) the same as 
used in NDS consoles:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsrealtimeclockrtc">DS Real-Time Clock 
(RTC)</A><BR>The chip is accessed via 4bit I/O port (only 3bits are used for 
RTC):<BR><A href="http://nocash.emubase.de/gbatek.htm#gbacartioportgpio">GBA 
Cart I/O Port (GPIO)</A><BR><BR><B>Comparision of RTC Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS_________GBA_________GBA/Params___
  stat2       control     (1-byte)
  datetime    datetime    (7-byte)
  time        time        (3-byte)
  stat1       force reset (0-byte)
  clkadjust   force irq   (0-byte)
  alarm1/int1 always FFh  (boktai contains code for writing 1-byte to it)
  alarm2      always FFh  (unused)
  free        always FFh  (unused)
</PRE></TD></TR></TBODY></TABLE><BR><B>Control Register</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit Dir Expl.
  0   -   Not used
  1   R/W IRQ duty/hold related?
  2   -   Not used
  3   R/W Per Minute IRQ (30s duty)        (0=Disable, 1=Enable)
  4   -   Not used
  5   R/W Unknown?
  6   R/W 12/24-hour Mode                  (0=12h, 1=24h) (usually 1)
  7   R   Power-Off (auto cleared on read) (0=Normal, 1=Failure)
</PRE></TD></TR></TBODY></TABLE>Setting after Battery-Shortcut is 82h. Setting 
after Force-Reset is 00h.<BR>Unused bits seem to be always zero, but might be 
read-only or write-only?<BR><BR><B>Datetime and Time Registers</B><BR>Same as 
NDS, except AM/PM flag moved from hour.bit6 (NDS) to hour.bit7 
(GBA).<BR><BR><B>Force Reset/Irq Registers</B><BR>Used to reset all RTC 
registers (all used registers become 00h, except day/month which become 01h), or 
to drag the IRQ output LOW for a short moment. These registers are strobed by 
ANY access to them, ie. by both writing to, as well as reading from these 
registers.<BR><BR><B>Pin-Outs / IRQ Signal</B><BR>The package has identical 
pin-outs as in NDS, although it is slightly larger than the miniature chip in 
the DS.<BR>For whatever reason, the RTC's /IRQ output is passed through an 
inverter (contained in the ROM-chip), the inverted signal is then passed to the 
/IRQ pin on the cartridge slot. So, IRQ's will be triggered on the "wrong" edge 
- possible somehow in relation with detecting cartridge-removal 
IRQs?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartsolarsensor></A><FONT size=+2>&nbsp;GBA Cart Solar 
      Sensor</FONT></TD></TR></TBODY></TABLE><BR>Uses a Photo Diode as Solar Sensor 
(used in Boktai, allowing to defeat vampires when the cartridge is exposed to 
sunlight). The cartridge comes in transparent case, and it's slightly longer 
than normal carts, so the sensor reaches out of the cartridge slot. According to 
the manual, the sensor works only with sunlight, but actually it works with any 
strong light source (eg. a 100 Watt bulb at 1-2 centimeters distance). The 
sensor is accessed via 4bit I/O port (only 3bits used), which is contained in 
the ROM-chip.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartioportgpio">GBA Cart I/O Port 
(GPIO)</A><BR><BR><B>A/D Conversion</B><BR>The cartridge uses a self-made A/D 
converter, which is (eventually) better than measuring a capacitor charge-up 
time, and/or less expensive than a real ADC-chip:<BR>It contains a 74LV4040 
12bit binary counter (clocked by CPU via the I/O port), of which only the lower 
8bit are used, which are passed to a resistor ladder-type D/A converter, which 
is generating a linear increasing voltage, which is passed to a TLV272 voltage 
comparator, which is passing a signal to the I/O port when the counter voltage 
becomes greater than the sensor voltage.<BR><BR><B>Example Code</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  strh  0001h,[80000c8h] ;-enable R/W mode
  strh  0007h,[80000c6h] ;-init I/O direction
  strh  0002h,[80000c4h] ;-reset counter to zero (high=reset) (I/O bit0)
  strh  0000h,[80000c4h] ;-clear reset (low=normal)
  mov   r0,0             ;-initial level
 @@lop:
  strh  0001h,[80000c4h] ;-clock high ;\increase counter      (I/O bit1)
  strh  0000h,[80000c4h] ;-clock low  ;/
  ldrh  r1,[80000c4h]    ;-read port                          (I/O bit3)
  tst   r1,08h           ;\
  addeq r0,1             ; loop until voltage match (exit with r0=00h..FFh),
  tsteq r0,100h          ; or until failure/timeout (exit with r0=100h)
  beq   @@lop            ;/
</PRE></TD></TR></TBODY></TABLE>The results vary depending on the clock rate 
used. In above example, ensure that IRQs or DMAs do not interrupt the function. 
Alternately, use a super-slow clock rate (eg. like 666Hz used in Boktai) so that 
additional small IRQ/DMA delays have little effect on the overall timing. 
Results should be somewhat:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  E8h  total darkness (including daylight on rainy days)
  Dxh  close to a 100 Watt Bulb
  5xh  reaches max level in boktai's solar gauge
  00h  close to a tactical nuclear bomb dropped on your city
</PRE></TD></TR></TBODY></TABLE>The exact values may change from cartridge to 
cartridge, so it'd be recommened to include a darkness calibration function, 
prompting the user to cover the sensor for a moment.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacarttiltsensor></A><FONT size=+2>&nbsp;GBA Cart Tilt 
      Sensor</FONT></TD></TR></TBODY></TABLE><BR>Yoshi's Universal Gravitation / Yoshi 
Topsy Turvy (X/Y-Axis)<BR>Koro Koro Puzzle (probably same as Yoshi, X/Y-Axis, 
too) (?)<BR><BR><B>Yoshi-Type (X/Y-Axis)</B><BR>All of the registers are one 
byte wide, mapped into the top "half" of the SRAM memory range.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  E008000h (W) Write 55h to start sampling
  E008100h (W) Write AAh to start sampling
  E008200h (R) Lower 8 bits of X axis
  E008300h (R) Upper 4 bits of X axis, and Bit7: ADC Status (0=Busy, 1=Ready)
  E008400h (R) Lower 8 bits of Y axis
  E008500h (R) Upper 4 bits of Y axis
</PRE></TD></TR></TBODY></TABLE>You must set SRAM wait control to 8 clocks to 
access it correctly.<BR>You must also set the cartridge PHI terminal to 4 MHz to 
make it work.<BR>Sampling routine (typically executed once a frame during 
VBlank):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  wait until [E008300h].Bit7=1 or until timeout ;wait ready
  x = ([E008300h] AND 0Fh)*100h + [E008200h]    ;get x
  y = ([E008500h] AND 0Fh)*100h + [E008400h]    ;get y
  [E008000h]=55h, [E008100h]=AAh                ;start next conversion
</PRE></TD></TR></TBODY></TABLE>Example values (may vary on different carts and 
on temperature, etc):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  X ranged between 0x2AF to 0x477, center at 0x392.    Huh?
  Y ranged between 0x2C3 to 0x480, center at 0x3A0.    Huh?
</PRE></TD></TR></TBODY></TABLE>Thanks to Flubba for Yoshi-Type 
information.<BR>Unknown if the Yoshi-Type sensors are sensing rotation, or 
orientation, or motion, or something else? In case of rotation, rotation around 
X-axis would result in motion in Y-direction, so not too sure whether X and Y 
have which meaning?<BR>Most probably, the sensors are measuring (both) static 
acceleration (gravity), and dynamic acceleration (eg. shaking the device 
left/right).<BR>The X/Y values are likely to be mirrored depending on using a 
back-loading cartridge slot (original GBA), or front-loading cartridge slot 
(newer GBA SP, and NDS, and NDS-Lite).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartgyrosensor></A><FONT size=+2>&nbsp;GBA Cart Gyro 
      Sensor</FONT></TD></TR></TBODY></TABLE><BR>Warioware Twisted (Z-Axis Gyro 
Sensor, plus Rumble)<BR><BR><B>Wario-Type (Z-Axis)</B><BR>Uses a single-axis 
sensor, which senses rotation around the Z-axis. The sensor is connected to an 
analogue-in, serial-out ADC chip, which is accessed via lower 3 bits of the 
GPIO,<BR><A href="http://nocash.emubase.de/gbatek.htm#gbacartioportgpio">GBA 
Cart I/O Port (GPIO)</A><BR>The four I/O Lines are connected like so,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GPIO.Bit0 (W) Start Conversion
  GPIO.Bit1 (W) Serial Clock
  GPIO.Bit2 (R) Serial Data
  GPIO.Bit3 (W) Used for Rumble (not gyro related)
</PRE></TD></TR></TBODY></TABLE>There should be at least &lt;three sequential 
32bit ARM opcodes executed in WS0 region&gt; between the STRH opcodes which 
toggle the CLK signal. Wario uses WAITCNT=45B7h (SRAM=8clks, 
WS0/WS1/WS2=3,1clks, Prefetch=On, PHI=Off).<BR>The data stream consists of: 4 
dummy bits (usually zero), followed by 12 data bits, followed by endless unused 
bits (usually zero).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> read_gyro:
  mov  r1,8000000h      ;-cartridge base address
  mov  r0,01h           ;\enable R/W access
  strh r0,[r1,0c8h]     ;/
  mov  r0,0bh           ;\init direction (gpio2=input, others=output)
  strh r0,[r1,0c6h]     ;/
  ldrh r2,[r1,0c4h]     ;-get current state (for keeping gpio3=rumble)
  orr  r2,3                     ;\
  strh r2,[r1,0c4h] ;gpio0=1    ; start ADC conversion
  bic  r2,1                     ;
  strh r2,[r1,0c4h] ;gpio0=0    ;/
  mov  r0,00010000h ;stop-bit           ;\
  bic  r2,2                             ;
 @@lop:                                 ;
  ldrh r3,[r1,0c4h] ;get gpio2=data     ; read 16 bits
  strh r2,[r1,0c4h] ;gpio1=0=clk=low    ; (4 dummy bits, plus 12 data bits)
  movs r3,r3,lsr 3  ;gpio2 to cy=data   ;
  adcs r0,r0,r0     ;merge data, cy=done;
  orr  r3,r2,2      ;set bit1 and delay ;
  strh r3,[r1,0c4h] ;gpio1=1=clk=high   ;
  bcc  @@lop                            ;/
  bic  r0,0f000h                 ;-strip upper 4 dummy bits (isolate 12bit adc)
  bx   lr
</PRE></TD></TR></TBODY></TABLE>Example values (may vary on different carts, 
battery charge, temperature, etc):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  354h  rotated in anti-clockwise direction (shock-speed)
  64Dh  rotated in anti-clockwise direction (normal fast)
  6A3h  rotated in anti-clockwise direction (slow)
  6C0h  no rotation                         (stopped)
  6DAh  rotation in clockwise direction     (slow)
  73Ah  rotation in clockwise direction     (normal fast)
  9E3h  rotation in clockwise direction     (shock-speed)
</PRE></TD></TR></TBODY></TABLE>For detection, values 000h and FFFh would 
indicate that there's no sensor.<BR>The Z-axis always points into same 
direction; no matter of frontloading or backloading cartridge slots.<BR>Thanks 
to Momo Vampire for contributing a Wario 
cartridge.<BR><BR><B>X/Y/Z-Axes</B><BR>X-Axis and Y-Axis are meant to be 
following the screens X and Y coordinates, so the Z-Axis would point into the 
screens depth direction.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartrumble></A><FONT size=+2>&nbsp;GBA Cart 
  Rumble</FONT></TD></TR></TBODY></TABLE><BR>Warioware Twisted (Rumble, plus 
Z-Axis Gyro Sensor)<BR>Drill Dozer (Rumble only)<BR><BR>GBA Rumble Carts are 
containing a small motor, which is causing some vibration when/while it is 
switched on (that, unlike DS Rumble, which must be repeatedly toggled 
on/off).<BR><BR>In Warioware Twisted, rumble is controlled via GPIO.Bit3 (Data 
0=Low=Off, 1=High=On) (and Direction 1=Output), the other GPIO Bits are used for 
the gyro sensor.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartioportgpio">GBA Cart I/O Port 
(GPIO)</A><BR>Note: GPIO3 is connected to an external pulldown resistor (so the 
HighZ level gets dragged to Low=Off when direction is set to 
Input).<BR><BR>Unknown if Drill Dozer is controlled via GPIO.Bit3, 
too?<BR><BR><B>DS Rumble Pak</B><BR>Additionally, there's a Rumble Pak for the 
NDS, which connects to the GBA slot, so it can be used also for GBA games 
(provided that the game doesn't require the GBA slot, eg. GBA multiboot 
games).<BR><A href="http://nocash.emubase.de/gbatek.htm#dscartrumblepak">DS Cart 
Rumble Pak</A><BR><BR><B>Gamecube Rumble</B><BR>Moreover, GBA games that are 
running on a Gameboy Player are having access to the Rumble function of Gamecube 
joypads.<BR><A href="http://nocash.emubase.de/gbatek.htm#gbagameboyplayer">GBA 
Gameboy Player</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereader></A><FONT size=+2>&nbsp;GBA Cart 
    e-Reader</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderoverview">GBA Cart 
e-Reader Overview</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderioports">GBA Cart 
e-Reader I/O Ports</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderdotcodeformat">GBA Cart 
e-Reader Dotcode Format</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderdataformat">GBA Cart 
e-Reader Data Format</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderprogramcode">GBA Cart 
e-Reader Program Code</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderapifunctions">GBA Cart 
e-Reader API Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereadervpkdecompression">GBA 
Cart e-Reader VPK Decompression</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereadererrorcorrection">GBA 
Cart e-Reader Error Correction</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartereaderfileformats">GBA Cart 
e-Reader File Formats</A><BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>   ________________
  |   ShortStrip   |
  |L              L|
  |o    Center    o|
  |n    Region    n|
  |g              g|
  |  may contain   |
  |S   pictures,  S|
  |t instructions t|
  |r     etc.     r|
  |i              i|
  |p              p|
  |___ShortStrip___|
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderoverview></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader Overview</FONT></TD></TR></TBODY></TABLE><BR>The e-Reader is a large 
GBA cartridge (about as big as the GBA console), with built-in dotcode scanning 
hardware. Dotcodes are tiny strips of black and white pixels printed on the 
edges of cardboard cards. The cards have to be pulled through a slot on the 
e-Reader, which is giving it a feeling like using a magnet card reader. The 
binary data on the dotcodes contains small games, either in native GBA code 
(ARM/THUMB), or in software emulated 8bit Z80 or NES/Famicom (6502) 
code.<BR><BR><B>The e-Reader Hardware</B><BR>The hardware consists of regular 
8MByte ROM and 128KByte FLASH chips, two link ports, a custom PGA chip, the 
camera module (with two red LEDs, used as light source), and some analogue 
components for generating the LED voltages, etc. The camera supports 402x302 
pixels with 7bit monochrome color depth, but the PGA clips it to max 320 pixels 
per scanline with 1bit color depth.<BR><BR><B>Link Port Plug/Socket</B><BR>The 
e-Reader's two link ports are simply interconnected with each other; without 
connection to the rest of the e-Reader hardware. These ports are used only on 
the original GBA (where the large e-Reader cartridge would be covering the GBA's 
link socket). When trying to insert the e-Reader into an original NDS, then the 
e-Reader's link plug will hit against the case of the NDS, so it works only with 
some minor modification to the hardware. There's no such problem with GBA-SP and 
NDS-Lite.<BR><BR><B>Region/Version</B><BR>There are 3 different e-Reader's: 
Japanese/Original, Japanese/Plus, and Non-Japanese. The Original version has 
only 64K FLASH, no Link Port, and reportedly supports only Z80 code, but no 
NES/GBA code. The Plus and Non-Japanese versions should be almost identical, 
except that they reject cards from the wrong region, and that the title strings 
aren't ASCII in Japan, the Plus version should be backwards compatible to the 
Original one.<BR><BR><B>The Problem</B><BR>Nintendo's current programmers are 
definetly unable to squeeze a Pac-Man style game into less than 4MBytes. Their 
solution has been: MORE memory. That is, they've put a whopping 8MByte BIOS ROM 
into the e-Reader, which contains the User Interface, and software emulation for 
running some of their 20 years old 8bit NES and Game&amp;Watch titles, which do 
fit on a few dotcode strips.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderioports></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader I/O Ports</FONT></TD></TR></TBODY></TABLE><BR><B>DF80000h Useless 
Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Output to PGA.Pin93 (which seems to be not connected to anything)
  1-3   Unknown, read/write-able (not used by e-Reader BIOS)
  4-15  Always zero (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>DFA0000h Reset Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0    Always zero              (0)
  1    Reset Something?         (0=Normal, 1=Reset)
  2    Unknown, always set      (1)
  3    Unknown, read/write-able (not used by e-Reader BIOS)
  4-7  Always zero              (0)
  8    Unknown, read/write-able (not used by e-Reader BIOS)
  9-15 Always zero              (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>DFC0000h..DFC0027h Scanline Data 
(R)</B><BR>Scanline data (40 bytes, for 320 pixels, 1bit per pixel, 0=black, 
1=white).<BR>The first (leftmost) pixel is located in the LSB of the LAST 
byte.<BR>Port E00FFB1h.Bit1 (and [4000202h].Bit13) indicates when a new scanline 
is present, the data should be then transferred to RAM via DMA3 (SAD=DFC0000h, 
DAD=buf+y*28h, CNT=80000014h; a slower non-DMA transfer method would result in 
missed scanlines). After the DMA, software must reset E00FFB1h.Bit1.<BR>Note: 
The scanning resolution is 1000 DPI.<BR><BR><B>DFC0028h+(0..2Fh*2) Brightest 
Pixels of 8x6 Blocks (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-6  Max Brightness (00h..7Fh; 00h=All black, 7Fh=One or more white)
  7-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Can be used to adjust the Port 
E00FF80h..E00FFAFh settings.<BR><BR><B>DFC0088h Darkest Pixel of whole Image 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7  Max Darkness   (00h..7Fh; 00h=One or more black, 7Fh=All white)
  8-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Can be used to adjust the Port 
E00FF80h..E00FFAFh settings.<BR><BR><B>E00FF80h..E00FFAFh Intensity Boundaries 
for 8x6 Blocks (R/W)</B><BR>The 320x246 pixel camera input is split into 8x6 
blocks (40x41 pixels each), with Block00h=Upper-right, Block07h=Upper-left, ..., 
Block27h=Lower-left. The boundary values for the separate blocks are used for 
128-grayscale to 2-color conversion, probably done like "IF Pixel&gt;Boundary 
THEN white ELSE black".<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-6  Block Intensity Boundaries (0..7Fh; 7Fh=Whole block gets black)
  7    Always zero
</PRE></TD></TR></TBODY></TABLE>The default boundary values are stored in FLASH 
memory, the values are typically ranging from 28h (outer edges) to 34h (center 
image), that in respect to the light source (the two LEDs are emitting more 
light to the center region).<BR><BR><B>E00FFB0h Control Register 0 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0    Serial Data       (Low/High)
  1    Serial Clock      (Low/High)
  2    Serial Direction  (0=Input, 1=Output)
  3    Led/Irq Enable    (0=Off, 1=On; Enable LED and Gamepak IRQ)
  4    Start Scan        (0=Off, 1=Start) (0-to-1 --&gt; Resync line 0)
  5    Phi 16MHz Output  (0=Off, 1=On; Enable Clock for Camera, and for LED)
  6    Power 3V Enable   (0=Off, 1=On; Enable 3V Supply for Camera)
  7    Not used          (always 0) (sometimes 1) (Read only)
</PRE></TD></TR></TBODY></TABLE><BR><B>E00FFB1h Control Register 1 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0    Not used          (always 0)
  1    Scanline Flag     (1=Scanline Received, 0=Acknowledge)
  2-3  Not used          (always 0)
  4    Strange Bit       (0=Normal, 1=Force Resync/Line0 on certain interval?)
  5    LED Anode Voltage (0=3.0V, 1=5.1V; requires E00FFB0h.Bit3+5 to be set)
  6    Not used          (always 0)
  7    Input from PGA.Pin22, always high (not used by e-Reader) (Read Only)
</PRE></TD></TR></TBODY></TABLE>Bit1 can be SET by hardware only, software can 
only RESET that bit, the Gamepak IRQ flag (Port 4000202h.Bit13) becomes set on 
0-to-1 transitions.<BR><BR><B>E00FFB2h Light Source LED Kathode Duration (LSB) 
(R/W)</B><BR><B>E00FFB3h Light Source LED Kathode Duration (MSB) 
(R/W)</B><BR>Selects the LED Kathode=LOW Duration, aka the LED=ON Duration. That 
does act as pulse width modulated LED brightness selection (the camera seems to 
react slowly enough to view the light as being dimmed to medium, rather than 
seeing the actual light ON and OFF states). The PWM timer seems to be clocked at 
8MHz. The hardware clips timer values 2000h..FFFFh to max 2000h (=1ms). 
Additionally, the e-Reader BIOS clips values to max 11B3h. Default setting is 
found in FLASH calibration data. A value of 0000h disables the 
LED.<BR><BR><B>Serial Port Registers (Camera Type 1) (DV488800) 
(calib_data[3Ch]=1)</B><BR>All 16bit values are ordered MSB,LSB. All registers 
are whole 8bit Read/Write-able, except 00h,57h-5Ah (read only), and 53h-55h 
(2bit only).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Port     Expl.               (e-Reader Setting)
  00h      Maybe Chip ID (12h) (not used by e-Reader BIOS) (Read Only)
  01h                          (05h)    ;-Bit0: 1=auto-repeat scanning?
  02h                          (0Eh)
  10h-11h  Vertical Scroll     (calib_data[30h]+7)
  12h-13h  Horizontal Scroll   (0030h)
  14h-15h  Vertical Size       (00F6h=246)
  16h-17h  Horizontal Size     (0140h=320)
  20h-21h  H-Blank Duration    (00C4h)
  22h-23h                      (0400h)  ;-Upper-Blanking in dot-clock units?
  25h                          (var)    ;-bit1: 0=enable [57h..5Ah] ?
  26h                          (var)    ;\maybe a 16bit value
  27h                          (var)    ;/
  28h                          (00h)
  30h      Brightness/contrast (calib_data[31h]+/-nn)
  31h-33h                      (014h,014h,014h)
  34h      Brightness/contrast (02h)
  50h-52h  8bit Read/Write     (not used by e-Reader BIOS)
  53h-55h  2bit Read/Write     (not used by e-Reader BIOS)
  56h      8bit Read/Write     (not used by e-Reader BIOS)
  57h-58h  16bit value, used to autodetect/adjust register[30h] (Read Only)
  59h-5Ah  16bit value, used to autodetect/adjust register[30h] (Read Only)
  80h-FFh  Mirrors of 00h..7Fh (not used by e-Reader BIOS)
</PRE></TD></TR></TBODY></TABLE>All other ports are unused, writes to those 
ports are ignored, and reads are returning data mirrored from other ports; that 
is typically data from 2 or more ports, ORed together.<BR><BR><B>Serial Port 
Registers (Camera Type 2) (calib_data[3Ch]=2)</B><BR>All 16bit values are using 
more conventional LSB,MSB ordering, and port numbers are arranged in a more 
reasonable way. The e-Reader BIOS doesn't support (or doesn't require) 
brightness adjustment for this camera module.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Port     Expl.             (e-Reader Setting)
  00h                        (22h)
  01h                        (50h)
  02h-03h  Vertical Scroll   (calib_data[30h]+28h)
  04h-05h  Horizontal Scroll (001Eh)
  06h-07h  Vertical Size     (00F6h)    ;=246
  08h-09h  Horizontal Size   (0140h)    ;=320
  0Ah-0Ch                    (not used by e-Reader BIOS)
  0Dh                        (01h)
  0Eh-0Fh                    (01EAh)    ;=245*2
  10h-11h                    (00F5h)    ;=245
  12h-13h                    (20h,F0h)  ;maybe min/max values?
  14h-15h                    (31h,C0h)  ;maybe min/max values?
  16h                        (00h)
  17h-18h                    (77h,77h)
  19h-1Ch                    (30h,30h,30h,30h)
  1Dh-20h                    (80h,80h,80h,80h)
  21h-FFh                    (not used by e-Reader BIOS)
</PRE></TD></TR></TBODY></TABLE>My own e-Reader uses a Type 1 camera module. Not 
sure if Nintendo has ever manufactured any e-Readers with Type 2 
cameras?<BR><BR><B>Calibration Data in FLASH Memory (Bank 0, Sector 0Dh)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  E00D000 14h  ID String ('Card-E Reader 2001',0,0)
  E00D014 2    Sector Checksum (NOT(x+x/10000h); x=sum of all other halfwords)
</PRE></TD></TR></TBODY></TABLE>Begin of actual data (40h bytes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  E00D016 8x6  [00h] Intensity Boundaries for 8x6 blocks ;see E00FF80h..AFh
  E00D046 1    [30h] Vertical scroll (0..36h)  ;see type1.reg10h/type2.reg02h
  E00D047 1    [31h] Brightness or contrast    ;see type1.reg30h
  E00D048 2    [32h] LED Duration              ;see E00FFB2h..B3h
  E00D04A 2    [34h] Not used?   (0000h)
  E00D04C 2    [36h] Signed value, related to adjusting the 8x6 blocks
  E00D04E 4    [38h] Not used?   (00000077h)
  E00D052 4    [3Ch] Camera Type (0=none,1=DV488800,2=Whatever?)
</PRE></TD></TR></TBODY></TABLE>Remaining bytes in this Sector...<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  E00D056 FAAh Not used (zerofilled) (included in above checksum)
</PRE></TD></TR></TBODY></TABLE><BR><B>Flowchart for Overall Camera 
Access</B><BR>ereader_scan_camera:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> call ereader_power_on
 call ereader_initialize
 for z=1 to number_of_frames
  for y=0 to 245
   Wait until E00FFB1h.Bit1 gets set by hardware (can be handled by IRQ)
   Copy 14h halfwords from DFC0000h to buf+y*28h via DMA3
   Reset E00FFB1h.Bit1 by software
  next y
  ;(could now check DFC0028h..DFC0086h/DFC0088h for adjusting E00FF00h..2Fh)
  ;(could now show image on screen, that may require to stop/pause scanning)
 next z
 call ereader_power_off
 Ret
</PRE></TD></TR></TBODY></TABLE>ereader_power_on:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> [4000204h]=5803h   ;Init waitstates, and enable Phi 16MHz
 [DFA0000h].Bit1=1
 Wait(10ms)
 [E00FFB0h]=40h     ;Enable Power3V and reset other bits
 [DFA0000h].Bit1=0
 [E00FFB1h]=20h     ;Enable Power5V and reset other bits
 Wait(40ms)
 [E00FFB1h].Bit4=0  ;...should be already 0 ?
 [E00FFB0h]=40h+27h ;Phi16MHz=On, SioDtaClkDir=HighHighOut
 Ret
</PRE></TD></TR></TBODY></TABLE>ereader_power_off:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> [E00FFB0h]=04h    ;Power3V=Off, Disable Everything, SioDtaClkDir=LowLowOut
 [DFA0000h].Bit1=0 ;...should be already 0
 [E00FFB1h].Bit5=0 ;Power5V=Off
 Ret
</PRE></TD></TR></TBODY></TABLE>ereader_initialize:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> IF calib_data[3Ch] AND 03h = 1 THEN init_camera_type1
 [E00FFB0h].Bit4=1 ;ScanStart
 IF calib_data[3Ch] AND 03h = 2 THEN init_camera_type2
 Copy calib_data[00h..2Fh] to [E00FF80h+00h..2Fh]  ;Intensity Boundaries
 Copy calib_data[32h..33h] to [E00FFB2h+00h..01h]  ;LED Duration LSB,MSB
 [E00FFB0h].Bit3=1                                 ;LedIrqOn
 Ret
</PRE></TD></TR></TBODY></TABLE>init_camera_type1:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> x=MIN(0,calib_data[31h]-0Bh)
 Set Sio Registers (as shown for Camera Type 1, except below values...)
 Set Sio Registers [30h]=x [25h]=04h, [26h]=58h, [27h]=6Ch
 ;(could now detect/adjust &lt;x&gt; based on Sio Registers [57h..5Ah])
 Set Sio Registers [30h]=x [25h]=06h, [26h]=E8h, [27h]=6Ch
 Ret
</PRE></TD></TR></TBODY></TABLE>init_camera_type2:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Wait(0.5ms)
 Set Sio Registers (as shown for Camera Type 2)
 Ret
</PRE></TD></TR></TBODY></TABLE><BR><B>Accessing Serial Registers via 
E00FFB0h</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>      Begin   Write(A) Write(B) Read(C) Read(D) End     Idle    PwrOff
  Dir ooooooo ooooooo  ooooooo  iiiiiii iiiiiii ooooooo ooooooo ooooooo
  Dta ---____ AAAAAAA  BBBBBBB  xxxxxCx xxxxxDx ______- ------- _______
  Clk ------_ ___---_  ___---_  ___---_ ___---_ ___---- ------- _______
</PRE></TD></TR></TBODY></TABLE><BR><B>Flowchart for accessing Serial Registers 
via E00FFB0h</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Delay:
  Wait circa 2.5us, Ret
 SioBegin:
  SioDta=1, SioDir=Out, SioClk=1, Delay, SioDta=0, Delay, SioClk=0, Ret
 SioEnd:
  SioDta=0, SioDir=Out, Delay, SioClk=1, Delay, SioDta=1, Ret
 SioRead1bit:   ;out: databit
  SioDir=In, Delay, SioClk=1, Delay, databit=SioDta, SioClk=0, Ret
 SioWrite1bit:  ;in: databit
  SioDta=databit, SioDir=Out, Delay, SioClk=1, Delay, SioClk=0, Ret
 SioReadByte:   ;in: endflag - out: data
  for i=7 to 0, data.bit&lt;i&gt;=SioRead1bit, next i, SioWrite1bit(endflag), Ret
 SioWriteByte:  ;in: data - out: errorflag
  for i=7 to 0, Delay(huh/why?), SioWrite1bit(data.bit&lt;i&gt;), next i
  errorflag=SioRead1bit, SioDir=Out(huh/why?), Ret
 SioWriteRegisters:  ;in: index, len, buffer
  SioBegin
  SioWriteByte(22h)        ;command (set_index) (and write_data)
  SioWriteByte(index)      ;index
  for i=0 to len-1
   SioWriteByte(buffer[i]) ;write data (and auto-increment index)
  next
  SioEnd
  ret
 SioReadRegisters:   ;in: index, len - out: buffer
  SioBegin
  SioWriteByte(22h)        ;command (set_index) (without any write_data here)
  SioWriteByte(index)      ;index
  SioBegin
  SioWriteByte(23h)        ;command (read_data) (using above index)
  for i=0 to len-1
   if i=len-1 then endflag=1 else endflag=0
   buffer[i]=SioReadByte(endflag)  ;read data (and auto-increment index)
  next
  SioEnd
  Ret
</PRE></TD></TR></TBODY></TABLE>Caution: Accessing the SIO registers appears 
highly unstable, and seems to require error handling with retries. Not sure what 
is causing that problem, possibly the registers cannot be accessed during 
camera-data-scans...?<BR><BR><B>WAITCNT</B><BR>The e-Reader BIOS uses WAITCNT 
[4000204h]=5803h when accessing the PGA, that is, gamepak 16.78MHz phi output 
(bit11-12=3), 8 waits for SRAM region (bit0-1=3), gamepak prefetch enabled 
(bit14=1), also sets WS0 to 4,2 waits (bit2-4=0), and sets WS2 to odd 4,8 waits 
(bit8-10=0). The WS2 (probably WS0 too) settings are nonsense, and should work 
with faster timings (the e-Reader can be accessed in NDS mode, which doesn't 
support that slow timings).<BR><BR><B>e-Reader Memory and I/O Map (with all 
used/unused/mirrored regions)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  C000000h-C7FFFFFh  ROM (8MB)
  C800000h-DF7FFFFh  Open Bus
  DF80000h-DF80001h  Useless Register (R/W)
  DF80002h-DF9FFFFh  Mirrors of DF80000h-DF80001h
  DFA0000h-DFA0001h  Reset Register (R/W)
  DFA0002h-DFBFFFFh  Mirrors of DFA0000h-DFA0001h
  DFC0000h-DFC0027h  Scanline Data (320 Pixels) (R)
  DFC0028h-DFC0087h  Brightest Pixels of 8x6 Blocks (R)
  DFC0088h           Darkest Pixel of whole Image (R)
  DFC0089h-DFC00FFh  Always zero
  DFC0100h-DFDFFFFh  Mirrors of DFC0000h-DFC00FFh
  DFE0000h-DFFFFFFh  Open Bus
  E000000h-E00CFFFh  FLASH Bank 0 - Data
  E00D000h-E00DFFFh  FLASH Bank 0 - Calibration Data
  E00E000h-E00EFFFh  FLASH Bank 0 - Copy of Calibration Data
  E00F000h-E00FF7Fh  FLASH Bank 0 - Unused region
  E000000h-E00EFFFh  FLASH Bank 1 - Data
  E00F000h-E00FF7Fh  FLASH Bank 1 - Unused region
  E00FF80h-E00FFAFh  Intensity Boundaries for 8x6 Blocks (R/W)
  E00FFB0h           Control Register 0 (R/W)
  E00FFB1h           Control Register 1 (R/W)
  E00FFB2h-E00FFB3h  LED Duration (16bit) (R/W)
  E00FFB4h-E00FFBFh  Always zero
  E00FFC0h-E00FFFFh  Mirror of E00FF80h-E00FFBFh
</PRE></TD></TR></TBODY></TABLE>Mind that WS2 should be accessed by LDRH/STRH, 
and SRAM region by LDRB/STRB.<BR>Additionally about 32 serial bus registers are 
contained in the camera module.<BR><BR><B>Camera Module Notes</B><BR>The Type 1 
initial setting on power-on is 402x302 pixels, the e-Reader uses only 320x246 
pixels. The full vertical resolution could be probably used without problems. 
Port DFC0000h-DFC0027h are restricted to 320 pixels, so larger horizontal 
resolutions could be probably obtained only by changing the horizontal scroll 
offset on each 2nd scan.<BR>The camera output is 128 grayscales (via parallel 
7bit databus), but the PGA converts it to 2 colors (1bit depth). For still 
images, it might be possible to get 4 grayshades via 3 scans with different 
block intensity boundary settings.<BR>No idea if the camera supports serial 
commands other than 22h and 23h. Namely, it &lt;would&gt; be a quite obvious and 
basic feature to allow to receive the bitmap via the 2-wire serial bus 
(alternately to the 7bit databus), if supported, it'd allow to get 7bit images, 
bypassing 1bit PGA conversion.<BR>When used as actual camera (by cutting an 
opening in the case), the main problem is the 1bit color depth, which allows 
only black and white schemes, when/if solving that problem, focusing might be 
also a problem.<BR><BR>Either the camera or the PGA seem to have a problem on 
white-to-black transitions in vertical direction, the upper some black pixels 
are sorts of getting striped or dithered. For example, scanning the large sync 
marks appears as:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Actual Shape    Scanned Shape
     XXXXX            X  X
    XXXXXXX           X  X X
   XXXXXXXXX        X X  X XX
   XXXXXXXXX        X X  X XX
    XXXXXXX          XXXXXXX
     XXXXX            XXXXX
</PRE></TD></TR></TBODY></TABLE>That appears only on large black shapes (the 
smaller data dots look better).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderdotcodeformat></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader Dotcode Format</FONT></TD></TR></TBODY></TABLE><BR>Resolution is 342.39 
DPI (almost 10 blocks per inch).<BR>Resolution is 134.8 dots/cm (almost 4 blocks 
per centimeter).<BR>The width and height of the each block, and the spacing to 
the bottom edge of the card is ca. 1/10 inch, or ca. 4 millimeters.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>   XXX            BLOCK 1             XXX            BLOCK 2             XXX
  XXXXX                              XXXXX                              XXXXX
  XXXXX   X X X X X X  X X X X X X   XXXXX   X X X X X X  X X X X X X   XXXXX
  XXXXX                              XXXXX                              XXXXX
   XXX   HHHHHHHHHHHHHHHHHHHH......   XXX   HHHHHHHHHHHHHHHHHHHH......   XXX
         ..........................         ..........................
         ...... 3 short lines .....         ..........................
    A..................................A..................................A..
    A....      26 long lines       ....A........ X = Sync Marks   ........A..
    A....  (each 34 data dots)     ....A........ H = Block Header ........A..
    A....(not all lines shown here)....A........ . = Data Bits    ........A..
    A..................................A........ A = Address Bits ........A..
         ...... 3 short lines .....         ..........................
         ...(each 26 data dots)....         ..........................
   XXX   ..........................   XXX   ..........................   XXX
  XXXXX                              XXXXX                              XXXXX
  XXXXX   X X X X X X  X X X X X X   XXXXX   X X X X X X  X X X X X X   XXXXX
  XXXXX                              XXXXX                              XXXXX
   XXX                                XXX                                XXX
             &lt;ca. 35 blank lines&gt;
  ___Snip____________________________________________________________________
</PRE></TD></TR></TBODY></TABLE><BR><B>Address Columns</B><BR>Each Column 
consists of 26 dots. From top to bottom: 1 black dot, 8 blank dots, 16 address 
dots (MSB topmost), and 1 blank dot. The 16bit address values can be calculated 
as:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  addr[0] = 03FFh
  for i = 1 to 53
    addr[i] = addr[i-1] xor ((i and (-i)) * 769h)
    if (i and 07h)=0 then addr[i] = addr[i] xor (769h)
    if (i and 0Fh)=0 then addr[i] = addr[i] xor (769h*2)
    if (i and 1Fh)=0 then addr[i] = addr[i] xor (769h*4) xor (769h)
  next i
</PRE></TD></TR></TBODY></TABLE>Short strips use addr[1..19], long strips use 
addr[25..53], left to right.<BR><BR><B>Block Header</B><BR>The 18h-byte Block 
Header is taken from the 1st two bytes (20 dots) of the 1st 0Ch blocks (and is 
then repeated in the 1st two bytes of further blocks).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h      Unknown              (00h)
  01h      Dotcode type         (02h=Short, 03h=Long)
  02h      Unknown              (00h)
  03h      Address of 1st Block (01h=Short, 19h=Long)
  04h      Total Fragment Size  (40h) ;64 bytes per fragment, of which,
                                      ;48 bytes are actual data, the remaining
  05h      Error-Info Size      (10h) ;16 bytes are error-info
  06h      Unknown              (00h)
  07h      Interleave Value     (1Ch=Short, 2Ch=Long)
  08h..17h 16 bytes Reed-solomon error correction info for Block Header
</PRE></TD></TR></TBODY></TABLE><BR><B>Data 4-Bit to 5-bit Conversion</B><BR>In 
the Block Header (HHHHH), and Data Region (.....), each 4bit are expanded to 
5bit, so one byte occupies 10 dots, and each block (1040 data dots) contains 104 
bytes.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4bit  00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh
  5bit  00h 01h 02h 12h 04h 05h 06h 16h 08h 09h 0Ah 14h 0Ch 0Dh 11h 10h
</PRE></TD></TR></TBODY></TABLE>That formatting ensures that there are no more 
than two continous black dots (in horizontal direction), neither inside of a 
5bit value, nor between two 5bit values, however, the address bars are violating 
that rule, and up to 5 continous black dots can appear at the (..A..) block 
boundaries.<BR><BR><B>Data Order</B><BR>Data starts with the upper bit of the 
5bit value for the upper 4bit of the first byte, which is located at the 
leftmost dot of the upper line of the leftmost block, it does then extend 
towards rightmost dot of that block, and does then continue in the next line, 
until reaching the bottom of the block, and does then continue in the next 
block. The 1st two bytes of each block contain a portion of the Block Header, 
the remaining 102 bytes in each block contain data.<BR><BR><B>Data Size</B><BR>A 
long strip consists of 28 blocks (28*104 = 2912 bytes), a short strip of 18 
blocks (18*104 = 1872 bytes). Of which, less than 75% can be actually used for 
program code, the remaing data contains error correction info, and various 
headers. See Data Format for more info.<BR><BR><B>Interleaved 
Fragments</B><BR>The Interleave Value (I) specifies the number of fragments, and 
does also specify the step to the next byte inside of a fragment; except that, 
at the block boundaries (every 104 bytes), the step is 2 bigger (for skipping 
the next two Block Header bytes).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RAW Offset  Content
  000h..001h  1st 2 bytes of RAW Header
  002h        1st byte of 1st fragment
  003h        1st byte of 2nd fragment
  ...         ...
  002h+I-1    1st byte of last fragment
  002h+I      2nd byte of 1st fragment
  003h+I      2nd byte of 2nd fragment
  ...         ...
  002h+I*2-1  2nd byte of last fragment
  ...         ...
</PRE></TD></TR></TBODY></TABLE>Each fragment consists of 48 actual data bytes, 
followed by 16 error correction bytes, followed by 0..2 unused bytes (since 
I*40h doesn't exactly match num_blocks*102).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderdataformat></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader Data Format</FONT></TD></TR></TBODY></TABLE><BR><B>Data Strip 
Format</B><BR>The size of the data region is I*48 bytes (I=Interleave Value, see 
Dotcode Format), the first 48-byte fragment contains the Data Header, the 
remaining (I-1) fragments are Data Fragments (which contain title(s), and VPK 
compressed program code).<BR><BR><B>First Strip</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Data Header  (48 bytes)
  Main-Title   (17 bytes, or 33 bytes)
  Sub-Title(s) (3+18 bytes, or 33 bytes) (for each strip) (optional)
  VPK Size     (2 byte value, total length of VPK Data in ALL strips)
  NULL Value   (4 bytes, contained ONLY in 1st strip of GBA strips)
  VPK Data     (length as defined in VPK Size entry, see above)
</PRE></TD></TR></TBODY></TABLE><BR><B>Further Strip(s)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Data Header  (48 bytes)
  Main-Title   (17 bytes, or 33 bytes)
  Sub-Title(s) (3+18 bytes, or 33 bytes) (for each strip) (optional)
  VPK Data     (continued from previous strip)
</PRE></TD></TR></TBODY></TABLE><BR><B>Data Header (30h bytes) (1st 
fragment)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h-01h  Fixed         (00h,30h)
  02h      Fixed         (01h)     ;01h="Do not calculate Global Checksum" ?
  03h      Primary Type  (see below)
  04h-05h  Fixed         (00h,01h) (don't care)
  06h-07h  Strip Size    (0510h=Short, 0810h=Long Strip) ((I-1)*30h) (MSB,LSB)
  08h-0Bh  Fixed         (00h,00h,10h,12h)
  0Ch-0Dh  Region/Type   (see below)
  0Eh      Strip Type    (02h=Short Strip, 01h=Long Strip) (don't care)
  0Fh      Fixed         (00h) (don't care)
  10h-11h  Unknown       (whatever) (don't care)
  12h      Fixed         (10h)     ;10h="Do calculate Data Checksum" ?
  13h-14h  Data Checksum (see below) (MSB,LSB)
  15h-19h  Fixed         (19h,00h,00h,00h,08h)
  1Ah-21h  ID String     ('NINTENDO')
  22h-25h  Fixed         (00h,22h,00h,09h)
  26h-29h  Size Info     (see below)
  2Ah-2Dh  Flags         (see below)
  2Eh      Header Checksum (entries [0Ch-0Dh,10h-11h,26h-2Dh] XORed together)
  2Fh      Global Checksum (see below)
</PRE></TD></TR></TBODY></TABLE>Primary Type [03h] is 8bit,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0      Card Type (upper bit) (see below)
  1      Unknown (usually opposite of Bit0) (don't care)
  2-7    Unknown (usually zero)
</PRE></TD></TR></TBODY></TABLE>Region/Type [0Ch..0Dh] is 16bit,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3    Unknown (don't care)
  4-7    Card Type (lower bits) (see below)
  8-11   Region/Version (0=Japan/Original, 1=Non-japan, 2=Japan/Plus)
  12-15  Unknown (don't care)
</PRE></TD></TR></TBODY></TABLE>Size Info [26h-29h] is 32bit,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0      Unknown            (don't care)
  1-4    Strip Number       (01h..Number of strips)
  5-8    Number of Strips   (01h..0Ch) (01h..08h for Japan/Original version)
  9-23   Size of all Strips (excluding Headers and Main/Sub-Titles)
         (same as "VPK Size", but also including the 2-byte "VPK Size" value,
         plus the 4-byte NULL value; if it is present)
  24-31  Fixed              (02h) (don't care)
</PRE></TD></TR></TBODY></TABLE>Flags [2Ah-2Dh] is 32bit,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0      Permission to save (0=Start Immediately, 1=Prompt for FLASH Saving)
  1      Sub-Title Flag     (0=Yes, 1=None)    (Japan/Original: always 0=Yes)
  2      Application Type   (0=GBA/Z80, 1=NES) (Japan/Original: always 0=Z80)
  3-31   Zero (0) (don't care)
</PRE></TD></TR></TBODY></TABLE>Data Checksum [13h-14h] is the complement (NOT) 
of the sum of all halfwords in all Data Fragments, however, it's all done in 
reversed byte order: checksum is calculated with halfwords that are read in 
MSB,LSB order, and the resulting checksum is stored in MSB,LSB order in the 
Header Fragment.<BR>Global Checksum [2Fh] is the complement (NOT) of the sum of 
the first 2Fh bytes in the Data Header plus the sum of all Data Fragment 
checksums; the Data Fragment checksums are all 30h bytes in a fragment XORed 
with each other.<BR><BR><B>Titles (3+N bytes, or N bytes)</B><BR>Titles can be 
33 bytes for both Main and Sub (Format 0Eh), or Main=17 bytes and Sub=3+18 bytes 
(Formats 02h..05h). In the 3+N bytes form, the first 3 bytes (24bit) are are 
used to display "stats" information in form of "HP: h1 ID: i1-i2-i3", defined 
as:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  0-3    h1, values 1..15 shown as "10..150", value 0 is not displayed
  4-6    i3, values 0..7 shown as "A..G,#"
  7-13   i2, values 0..98 shown as "01..99" values 99..127 as "A0..C8"
  14-18  i1, values 0..31 shown as "A..Z,-,_,{HP},.,{ID?},:"
  19-22  Unknown
  23     Disable stats (0=Show as "HP: h1 ID: i1-i2-i3", 1=Don't show it)
</PRE></TD></TR></TBODY></TABLE>The N bytes portion contains the actual title, 
which must be terminated by 00h (so the max length is N-1 characters, if it is 
shorter than N-1, then the unused bytes are padded by further 00h's). The 
character set is normal ASCII for non-Japan (see Region/Version entry in 
header), and 2-byte SHIFT-JIS for Japanese long-titles (=max 16 2-byte chars) 
with values as so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h          --&gt; end-byte
  81h,40h      --&gt; SPC
  81h,43h..97h --&gt; punctuation marks
  82h,4Fh..58h --&gt; "0..9"
  82h,60h..79h --&gt; "A..Z"
  82h,81h..9Ah --&gt; "a..z"
</PRE></TD></TR></TBODY></TABLE>And 1-byte chars for Japanese short-titles,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00     = end-byte
  01     = spc
  02..0B = 0..9
  0C..AF = japanese
  B0..B4 = dash, male, female, comma, round-dot
  B5..C0 = !"%&amp;~?/+-:.'
  C1..DA = A..Z
  DB..DF = unused (blank)
  E0..E5 = japanese
  E6..FF = a..z
  N/A    = #$()*;&lt;=&gt;@[\]^_`{|}
</PRE></TD></TR></TBODY></TABLE>Additionally to the Main-Title, optional 
Sub-Titles for each strip can be included (see Sub-Title Flag in header). If 
enabled, then ALL strip titles are included in each strip (allowing to show a 
preview of which strips have/haven't been scanned yet).<BR>The e-Reader can 
display maximum of 8 sub-titles, if the data consists of more than 8 strips, 
then sub-titles aren't displayed (so it'd be waste of space to include them in 
the dotcodes).<BR>The Main Title gets clipped to 128 pixels width (that are, 
circa 22 characters), and, the e-Reader BIOS acts confused on multi-strip games 
with Main Titles longer than 26 characters (so the full 33 bytes may be used 
only in Japan; with 16bit charset).<BR>If the title is empty (00h-filled), and 
there is only one card in the application, then the application is started 
immediately. That, without allowing the user to save it in FLASH 
memory.<BR>Caution: Although shorter Titles do save memory, they do act 
unpleasant: the text "(C) P-Letter" will be displayed at the bottom of the 
loading screen.<BR>On Japanese/Original, 8bit sub-titles can be up to 18 
characters (without any end-byte) (or less when stats are enabled, due to 
limited screen width).<BR><BR><B>Card Types (Primary Type.Bit0 and 
Region/Type.Bit12-15)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h..01h  Blank Screen (?)
  02h..03h  Dotcode Application with 17byte-title, with stats, load music A
  04h..05h  Dotcode Application with 17byte-title, with stats, load music B
  06h..07h  P-Letter Attacks
  08h..09h  Construction Escape
  0Ah..0Bh  Construction Action
  0Ch..0Dh  Construction Melody Box
  0Eh       Dotcode Application with 33byte-title, without stats, load music A
  0Fh       Game specific cards
  10h..1Dh  P-Letter Viewer
  1Eh..1Fh  Same as 0Eh and 0Fh (see above)
</PRE></TD></TR></TBODY></TABLE>The 'Application' types are meant to be 
executable GBA/Z80/NES programs.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderprogramcode></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader Program Code</FONT></TD></TR></TBODY></TABLE><BR>The GBA/Z80/NES 
program code is stored in the VPK compressed area.<BR>NES-type is indicated by 
header [2Ah].Bit2, GBA-type is indicated by the NULL value inserted between VPK 
Size and VPK Data, otherwise Z80-type is used.<BR><BR><B>GBA Format</B><BR>Load 
Address and Entrypoint are at 2000000h (in ARM state). The 32bit word at 
2000008h is eventually destroyed by the e-Reader. Namely,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  IF e-Reader is Non-Japanese,
  AND [2000008h] is outside of range of 2000000h..20000E3h,
  AND only if booted from camera (not when booted from FLASH?),
  THEN [2000008h]=[2000008h]-0001610Ch ELSE [2000008h] kept intact
</PRE></TD></TR></TBODY></TABLE>Existing multiboot-able GBA binaries can be 
converted to e-Reader format by,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Store "B 20000C0h" at 2000000h   ;redirect to RAM-entrypoint
  Zerofill 2000004h..20000BFh      ;erase header (for better compression rate)
  Store 01h,01h at 20000C4h        ;indicate RAM boot
</PRE></TD></TR></TBODY></TABLE>The GBA code has full access to the GBA 
hardware, and may additionally use whatever API functions contained in the 
e-Reader BIOS. With the incoming LR register value, "mov r0,N, bx lr" returns to 
the e-Reader BIOS (with N being 0=Restart, or 2=To_Menu). No idea if it's 
necessary to preserve portions of RAM when returning to the e-Reader 
BIOS?<BR>Caution: Unlike for normal GBA cartridges/multiboot files, the hardware 
is left uninitialized when booting dotcodes (among others: sound DMA is active, 
and brightness is set to zero), use "mov r0,0feh, swi 010000h" to get the normal 
settings.<BR><BR><B>NES Format</B><BR>Emulates a NES (Nintendo Entertainment 
System) console (aka Family Computer).<BR>The visible 240x224 pixel NES/NTSC 
screen resolution is resampled to 240x160 to match the smaller vertical 
resolution of the GBA hardware. So, writing e-Reader games in NES format will 
result in blurred screen output. The screen/sound/joypad is accessed via 
emulated NES I/O ports, program code is running on an emulated 6502 8bit CPU, 
for more info on the NES hardware, see no$nes debugger specifications, or<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  http://nocash.emubase.de/everynes.htm
</PRE></TD></TR></TBODY></TABLE>The e-Reader's NES emulator supports only 16K 
PRG ROM, followed by 8K VROM. The emulation accuracy is very low, barely working 
with some of Nintendo's own NES titles; running the no$nes diagnostics program 
on it has successfully failed on ALL hardware tests ;-)<BR>The load address for 
the 16K PRG-ROM is C000h, the 16bit NMI vector at [FFFAh] is encrypted like 
so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=17h to 0
   for j=07h to 0, nmi = nmi shr 1, if carry then nmi = nmi xor 8646h, next j
   nmi = nmi xor (byte[dmca_data+i] shl 8)
  next i
  dmca_data: db 0,0,'DMCA NINTENDO E-READER'
</PRE></TD></TR></TBODY></TABLE>The 16bit reset vector at [FFFCh] contains:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-14  Lower bits of Entrypoint (0..7FFFh = Address 8000h..FFFFh)
  Bit15    Nametable Mode (0=Vertical Mirroring, 1=Horizontal Mirroring)
</PRE></TD></TR></TBODY></TABLE>reportedly,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>   (NES limitations, 1 16K program rom + 1-2 8K CHR rom, mapper 0 and 1)
   ines mapper 1 would be MMC1, rather than CNROM (ines mapper 3)?
   but, there are more or less NONE games that have 16K PRG ROM + 16K VROM?
</PRE></TD></TR></TBODY></TABLE>The L+R Button key-combination allows to reset 
the NES, however, there seems to be no way to return to the e-Reader 
BIOS.<BR><BR><B>Z80/8080 Format</B><BR>The e-Reader doesn't support the 
following Z80 opcodes:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  CB [Prefix]     E0 RET PO   E2 JP PO,nn   E4 CALL PO,nn   27 DAA    76 HALT
  ED [Prefix]     E8 RET PE   EA JP PE,nn   EC CALL PE,nn   D3 OUT (n),A
  DD [IX Prefix]  F3 DI       08 EX AF,AF'  F4 CALL P,nn    DB IN A,(n)
  FD [IY Prefix]  FB EI       D9 EXX        FC CALL M,nn    xx RST 00h..38h
</PRE></TD></TR></TBODY></TABLE>That is leaving not more than six supported Z80 
opcodes (DJNZ, JR, JR c/nc/z/nz), everything else are 8080 opcodes. Custom 
opcodes are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  76 WAIT A frames, D3 WAIT n frames, and C7/CF RST 0/8 used for API calls.
</PRE></TD></TR></TBODY></TABLE>The load address and entrypoint are at 0100h in 
the emulated Z80 address space. The Z80 doesn't have direct access to the GBA 
hardware, instead video/sound/joypad are accessed via API functions, invoked via 
RST 0 and RST 8 opcodes, followed by an 8bit data byte, and with parameters in 
the Z80 CPU registers. For example, "ld a,02h, rst 8, db 00h" does return to the 
e-Reader BIOS.<BR>The Z80/8080 emulation is incredibly inefficient, written in 
HLL code, developed by somebody whom knew nothing about emulation nor about ARM 
nor about Z80/8080 processors.<BR><BR><B>Running GBA-code on Japanese/Original 
e-Reader</B><BR>Original e-Reader supports Z80 code only, but can be tweaked to 
run GBA-code:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  retry:
   ld bc,data // ld hl,00c8h      ;src/dst
  lop:
   ld a,[bc] // inc bc // ld e,a  ;lsb
   ld a,[bc] // inc bc // ld d,a  ;msb
   dw 0bcfh ;aka rst 8 // db 0bh  ;[4000000h+hl]=de
   inc hl // inc  hl // ld a,l
   cp a,0dch // jr nz,lop
  mod1 equ $+1
   dw 37cfh ;aka rst 8 // db 37h  ;bx 3E700F0h
  ;below executed only on jap/plus... on jap/plus, above 37cfh is hl=[400010Ch]
   ld a,3Ah // ld [mod1],a                  ;bx 3E700F0h (3Ah instead 37h)
   ld hl,1 // ld [mod2],hl // ld [mod3],hl  ;base (0200010Ch instead 0201610Ch)
   jr retry
  data:
  mod2 equ $+1
   dd loader         ;40000A4h dma2sad (loader)
   dd 030000F0h      ;40000A8h dma2dad (mirrored 3E700F0h)
   dd 8000000ah      ;40000ACh dma2cnt (copy 0Ah x 16bit)
  mod3 equ $+1
   dd main           ;40000B0h dma3sad (main)
   dd 02000000h      ;40000B4h dma3dad (2000000h)
  org $+201600ch     ;jap/plus: adjusted to org $+200000ch
   .align 2          ;alignment for 16bit-halfword
  loader:
   mov r0,80000000h  ;(dma3cnt, copy 10000h x 16bit)
   mov r1,04000000h  ;i/o base
   strb r1,[r1,208h] ;ime=0 (better disable ime before moving ram)
   str r0,[r1,0DCh]  ;dma3cnt (relocate to 2000000h)
   mov r15,2000000h  ;start relocated code at 2000000h in ARM state
  main:
   ;...insert/append whatever ARM code here...
   end
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderapifunctions></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader API Functions</FONT></TD></TR></TBODY></TABLE><BR><B>Z80 Interface 
(Special Opcodes)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  db 76h       ;Wait8bit A
  db D3h,xxh   ;Wait8bit xxh
  db C7h,xxh   ;RST0_xxh
  db CFh,xxh   ;RST8_xxh
  ld r,[00xxh]       ;get system values (addresses differ on jap/ori)
  ld r,[00C2h..C3h]  ;GetKeyStateSticky (jap/ori: 9F02h..9F03h)
  ld r,[00C4h..C5h]  ;GetKeyStateRaw    (jap/ori: 9F04h..9F05h)
  ld r,[00C0h..C1h]  ;see Exit and ExitRestart
  ld r,[00D0h..D3h]  ;see Mul16bit
</PRE></TD></TR></TBODY></TABLE>For jap/ori, 9Fxxh isn't forwards compatible 
with jap/plus, so it'd be better to check joypad via IoRead.<BR><BR><B>GBA 
Interface</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  bx [30075FCh] ;ApiVector ;in: r0=func_no,r1,r2,r3,[sp+0],[sp+4],[sp+8]=params
  bx lr         ;Exit      ;in: r0 (0=Restart, 2=To_Menu)
</PRE></TD></TR></TBODY></TABLE><BR><B>Wait8bit/Wait16bit</B><BR>The various 
Wait opcodes and functions are waiting as many frames as specified. Many API 
functions have no effect until the next Wait occurs.<BR><BR><B>Z80 RST0_xxh 
Functions / GBA Functions 02xxh</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RST0_00h FadeIn, A speed, number of frames (0..x)
  RST0_01h FadeOut
  RST0_02h BlinkWhite
  RST0_03h  (?)
  RST0_04h  (?) blend_func_unk1
  RST0_05h  (?)
  RST0_06h  (?)
  RST0_07h  (?)
  RST0_08h  (?)
  RST0_09h  (?) _020264CC_check
  RST0_0Ah  (?) _020264CC_free
  RST0_0Bh N/A (bx 0)
  RST0_0Ch N/A (bx 0)
  RST0_0Dh N/A (bx 0)
  RST0_0Eh N/A (bx 0)
  RST0_0Fh N/A (bx 0)
  RST0_10h LoadSystemBackground, A number of background (1..101), E bg# (0..3)
  RST0_11h SetBackgroundOffset, A=bg# (0..3), DE=X, BC=Y
  RST0_12h SetBackgroundAutoScroll
  RST0_13h SetBackgroundMirrorToggle
  RST0_14h  (?)
  RST0_15h  (?)
  RST0_16h  (?) write_000000FF_to_02029494_
  RST0_17h  (?)
  RST0_18h  (?)
  RST0_19h SetBackgroundMode, A=mode (0..2)
  RST0_1Ah  (?)
  RST0_1Bh  (?)
  RST0_1Ch  (?)
  RST0_1Dh  (?)
  RST0_1Eh  (?)
  RST0_1Fh  (?)
  RST0_20h LayerShow
  RST0_21h LayerHide
  RST0_22h  (?)
  RST0_23h  (?)
  RST0_24h ... [20264DCh+A*20h+1Ah]=DE, [20264DCh+A*20h+1Ch]=BC
  RST0_25h  (?)
  RST0_26h  (?)
  RST0_27h  (?)
  RST0_28h  (?)
  RST0_29h  (?)
  RST0_2Ah  (?)
  RST0_2Bh  (?)
  RST0_2Ch  (?)
  RST0_2Dh LoadCustomBackground, A bg# (0..3), DE pointer to struct_background,
           max. tile data size = 3000h bytes, max. map data size = 1000h bytes
  RST0_2Eh GBA: N/A - Z80: (?)
  RST0_2Fh  (?)
  RST0_30h CreateSystemSprite, - -   (what "- -" ???)
  RST0_31h SpriteFree, HL sprite handle
  RST0_32h SetSpritePos, HL=sprite handle, DE=X, BC=Y
  RST0_33h  (?) sprite_unk2
  RST0_34h SpriteFrameNext
  RST0_35h SpriteFramePrev
  RST0_36h SetSpriteFrame, HL=sprite handle, E=frame number (0..x)
  RST0_37h  (?) sprite_unk3
  RST0_38h  (?) sprite_unk4
  RST0_39h SetSpriteAutoMove, HL=sprite handle, DE=X, BC=Y
  RST0_3Ah  (?) sprite_unk5
  RST0_3Bh  (?) sprite_unk6
  RST0_3Ch SpriteAutoAnimate
  RST0_3Dh  (?) sprite_unk7
  RST0_3Eh SpriteAutoRotateUntilAngle
  RST0_3Fh SpriteAutoRotateByAngle
  RST0_40h SpriteAutoRotateByTime
  RST0_41h  (?) sprite_unk8
  RST0_42h SetSpriteAutoMoveHorizontal
  RST0_43h SetSpriteAutoMoveVertical
  RST0_44h  (?) sprite_unk9
  RST0_45h SpriteDrawOnBackground
  RST0_46h SpriteShow, HL=sprite handle
  RST0_47h SpriteHide, HL=sprite handle
  RST0_48h SpriteMirrorToggle
  RST0_49h  (?) sprite_unk10
  RST0_4Ah  (?) sprite_unk11
  RST0_4Bh  (?) sprite_unk12
  RST0_4Ch GetSpritePos
  RST0_4Dh CreateCustomSprite
  RST0_4Eh  (?)
  RST0_4Fh  (?) sprite_unk14
  RST0_50h  (?) sprite_unk15
  RST0_51h  (?) sprite_unk16
  RST0_52h  (?) sprite_unk17
  RST0_53h  (?) sprite_unk18
  RST0_54h  (?)
  RST0_55h  (?) sprite_unk20
  RST0_56h  (?)
  RST0_57h SpriteMove
  RST0_58h  (?) sprite_unk22
  RST0_59h  (?) sprite_unk23
  RST0_5Ah  (?) sprite_unk24
  RST0_5Bh SpriteAutoScaleUntilSize, C=speed (higher value is slower),
           HL=sprite handle, DE=size (0100h = normal size,
           lower value = larger, higher value = smaller)
  RST0_5Ch SpriteAutoScaleBySize
  RST0_5Dh SpriteAutoScaleWidthUntilSize
  RST0_5Eh SpriteAutoScaleHeightBySize
  RST0_5Fh  (?)
  RST0_60h  (?)
  RST0_61h  (?)
  RST0_62h  (?)
  RST0_63h  (?)
  RST0_64h hl=[[2024D28h+a*4]+12h]
  RST0_65h  (?) sprite_unk25
  RST0_66h SetSpriteVisible, HL=sprite handle, E=(0=not visible, 1=visible)
  RST0_67h  (?) sprite_unk26
  RST0_68h  (?) set_sprite_unk27
  RST0_69h  (?) get_sprite_unk27
  RST0_6Ah  (?)
  RST0_6Bh  (?)
  RST0_6Ch  (?)
  RST0_6Dh  (?)
  RST0_6Eh hl=[hl+000Ah]  ;r0=[r1+0Ah]
  RST0_6Fh  (?)
  RST0_70h  (?)
  RST0_71h  (?)
  RST0_72h  (?)
  RST0_73h  (?)
  RST0_74h  (?)
  RST0_75h  (?)
  RST0_76h  (?)
  RST0_77h  (?)
  RST0_78h  (?)
  RST0_79h  (?)
  RST0_7Ah  (?)
  RST0_7Bh  (?)
  RST0_7Ch  (?) _0202FD2C_unk12
  RST0_7Dh Wait16bit ;HL=num_frames (16bit variant of Wait8bit opcode/function)
  RST0_7Eh SetBackgroundPalette, HL=src_addr, DE=offset, C=num_colors (1..x)
  RST0_7Fh GetBackgroundPalette(a,b,c)
  RST0_80h SetSpritePalette, HL=src_addr, DE=offset, C=num_colors (1..x)
  RST0_81h GetSpritePalette(a,b,c)
  RST0_82h ClearPalette
  RST0_83h  (?) _0202FD2C_unk11
  RST0_84h  (?)
  RST0_85h  (?)
  RST0_86h  (?)
  RST0_87h  (?) _0202FD2C_unk8
  RST0_88h  (?) _0202FD2C_unk7
  RST0_89h  (?)
  RST0_8Ah  (?) _0202FD2C_unk6
  RST0_8Bh  (?) _0202FD2C_unk5
  RST0_8Ch GBA: N/A - Z80: (?)
  RST0_8Dh GBA: N/A - Z80: (?)
  RST0_8Eh  (?)
  RST0_8Fh WindowHide
  RST0_90h CreateRegion, H=bg# (0..3), L=palbank# (0..15),
           D,E,B,C=x1,y1,cx,cy (in tiles), return: n/a (no$note: n/a ???)
  RST0_91h SetRegionColor
  RST0_92h ClearRegion
  RST0_93h SetPixel
  RST0_94h GetPixel
  RST0_95h DrawLine
  RST0_96h DrawRect
  RST0_97h  (?) _0202FD2C_unk4
  RST0_98h SetTextColor, A=region handle, D=color foreground (0..15),
           E=color background (0..15)
  RST0_99h DrawText, A=region handle, BC=pointer to text, D=X, E=Y
           (non-japan uses ASCII text, but japanese e-reader's use STH ELSE?)
  RST0_9Ah SetTextSize
  RST0_9Bh  (?) RegionUnk7
  RST0_9Ch  (?) _0202FD2C_unk3
  RST0_9Dh  (?) _0202FD2C_unk2
  RST0_9Eh  (?) _0202FD2C_unk1
  RST0_9Fh Z80: (?) - GBA: SetBackgroundModeRaw
  RST0_A0h  (?)
  RST0_A1h  (?)
  RST0_A2h  (?) RegionUnk6
  RST0_A3h GBA: N/A - Z80: (?)
  RST0_A4h GBA: N/A - Z80: (?)
  RST0_A5h  (?)
  RST0_A6h  (?)
  RST0_A7h  (?)
  RST0_A8h  (?)
  RST0_A9h  (?)
  RST0_AAh  (?)
  RST0_ABh  (?)
  RST0_ACh  (?)
  RST0_ADh  (?) RegionUnk5
  RST0_AEh [202FD2Ch+122h]=A
  RST0_AFh [202FD2Ch+123h]=A
  RST0_B0h [202FD2Ch+124h]=A
  RST0_B1h  (?)
  RST0_B2h  (?)
  RST0_B3h GBA: N/A - Z80: Sqrt   ;hl=sqrt(hl)
  RST0_B4h GBA: N/A - Z80: ArcTan ;hl=ArcTan2(hl,de)
  RST0_B5h Sine                   ;hl=sin(a)*de
  RST0_B6h Cosine                 ;hl=cos(a)*de
  RST0_B7h  (?)
  RST0_B8h  (?)
  RST0_B9h N/A (bx 0)
  RST0_BAh N/A (bx 0)
  RST0_BBh N/A (bx 0)
  RST0_BCh N/A (bx 0)
  RST0_BDh N/A (bx 0)
  RST0_BEh N/A (bx 0)
  RST0_BFh N/A (bx 0)
<B>  Below Non-Japan and Japan/Plus only (not Japan/Ori)</B>
  RST0_C0h GetTextWidth(a,b)
  RST0_C1h GetTextWidthEx(a,b,c)
  RST0_C2h  (?)
  RST0_C3h Z80: N/A (bx 0) - GBA: (?)
  RST0_C4h  (?)
  RST0_C5h  (?)
  RST0_C6h  (?)
  RST0_C7h  (?)
  RST0_C8h  (?)
  RST0_C9h  (?)
  RST0_CAh  (?)
  RST0_CBh  (?)
  RST0_CCh  (?)
  RST0_CDh N/A (bx lr)
  RST0_CEh ;same as RST0_3Bh, but with 16bit mask
  RST0_CFh ;same as RST0_3Eh, but with 16bit de
  RST0_D0h ;same as RST0_3Fh, but with 16bit de
  RST0_D1h ;same as RST0_5Bh, but with 16bit de
  RST0_D2h ;same as RST0_5Ch, but with 16bit de
  RST0_D3h ;same as RST0_5Dh, but with 16bit de
  RST0_D4h ;same as RST0_5Eh, but with 16bit de
  RST0_D5h  (?)
  RST0_D6h  (?)
  RST0_D7h ;[202FD2Ch+125h]=A
  RST0_D8h  (?)
  RST0_D9h  (?)
  RST0_DAh  (?)
  RST0_DBh ;A=[3003E51h]
  RST0_DCh ;[3004658h]=01h
  RST0_DDh DecompressVPKorNonVPK
  RST0_DEh FlashWriteSectorSingle(a,b)
  RST0_DFh FlashReadSectorSingle(a,b)
  RST0_E0h SoftReset
  RST0_E1h GetCartridgeHeader     ;[hl+0..BFh]=[8000000h..80000BFh]
  RST0_E2h GBA: N/A - Z80: bx hl  ;in: hl=addr, af,bc,de,sp=param, out: a
  RST0_E3h Z80: N/A (bx 0) - GBA: (?)
  RST0_E4h  (?)
  RST0_E5h  (?)
  RST0_E6h  (?)
  RST0_E7h  (?)
  RST0_E8h  (?)
  RST0_E9h ;[2029498h]=0000h
  RST0_EAh Z80: N/A (bx 0) - GBA: InitMemory(a)
  RST0_EBh  (?) BL_irq_sio_dma3
  RST0_ECh ;hl = [3003E30h]*100h + [3003E34h]
  RST0_EDh FlashWriteSectorMulti(a,b,c)
  RST0_EEh FlashReadPart(a,b,c)
  RST0_EFh ;A=((-([2029416h] xor 1)) OR (+([2029416h] xor 1))) SHR 31
  RST0_F0h  (?) _unk1
  RST0_F1h RandomInit     ;in: hl=random_seed
  RST0_F2h                         (?)
<B>  Below Japan/Plus only</B>
  RST0_F3h  (?)
  RST0_F4h  (?)
  RST0_F5h  (?)
  RST0_F6h  (?)
  RST0_F7h GBA: N/A - Z80: (?)
<B>  Below is undefined/garbage (values as so in Z80 mode)</B>
  Jap/Ori: RST0_C0h      N/A (bx 0)
  Jap/Ori: RST0_C1h..FFh Overlaps RST8 jump list
  Non-Jap: RST0_F3h..FFh Overlaps RST8 jump list
  Jap/Pls: RST0_F8h..FFh Overlaps RST8 jump list
</PRE></TD></TR></TBODY></TABLE><BR><B>Z80 RST8_xxh Functions / GBA Functions 
01xxh</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RST8_00h GBA: N/A - Z80: Exit       ;[00C0h]=a ;(1=restart, 2=exit)
  RST8_01h GBA: N/A - Z80: Mul8bit    ;hl=a*e
  RST8_02h GBA: N/A - Z80: Mul16bit   ;hl=hl*de, s32[00D0h]=hl*de
  RST8_03h Div                        ;hl=hl/de
  RST8_04h DivRem                     ;hl=hl mod de
  RST8_05h PlaySystemSound            ;in: hl=sound_number
  RST8_06h  (?) sound_unk1
  RST8_07h Random8bit                 ;a=random(0..FFh)
  RST8_08h SetSoundVolume
  RST8_09h BcdTime                    ;[de+0..5]=hhmmss(hl*bc)
  RST8_0Ah BcdNumber                  ;[de+0..4]=BCD(hl), [de+5]=00h
  RST8_0Bh IoWrite                    ;[4000000h+hl]=de
  RST8_0Ch IoRead                     ;de=[4000000h+hl]
  RST8_0Dh GBA: N/A - Z80:  (?)
  RST8_0Eh GBA: N/A - Z80:  (?)
  RST8_0Fh GBA: N/A - Z80:  (?)
  RST8_10h GBA: N/A - Z80:  (?)
  RST8_11h DivSigned                  ;hl=hl/de, signed
  RST8_12h RandomMax                  ;a=random(0..a-1)
  RST8_13h SetSoundSpeed
  RST8_14h  hl=[202FD20h]=[2024CACh]
  RST8_15h  hl=[2024CACh]-[202FD20h]
  RST8_16h SoundPause
  RST8_17h SoundResume
  RST8_18h PlaySystemSoundEx
  RST8_19h IsSoundPlaying
  RST8_1Ah  (?)
  RST8_1Bh  (?)
  RST8_1Ch  (?)
  RST8_1Dh GetExitCount               ;a=[2032D34h]
  RST8_1Eh Permille                   ;hl=de*1000/hl
  RST8_1Fh GBA: N/A - Z80: ExitRestart;[2032D38h]=a, [00C0h]=0001h  ;a=?
  RST8_20h GBA: N/A - Z80: WaitJoypad ;wait until joypad&lt;&gt;0, set hl=joypad
  RST8_21h GBA: N/A - Z80:  (?)
  RST8_22h  (?) _sound_unk7
  RST8_23h  (?) _sound_unk8
  RST8_24h  (?) _sound_unk9
  RST8_25h  (?) _sound_unk10
  RST8_26h Mosaic     ;bg&lt;n&gt;cnt.bit6=a.bit&lt;n&gt;, [400004Ch]=de
  RST8_27h  (?)
  RST8_28h  (?)
  RST8_29h  (?)
  RST8_2Ah  (?) get_8bit_from_2030110h
  RST8_2Bh  (?)
  RST8_2Ch  (?) get_16bit_from_2030112h ;jap/ori: hl=[20077B2h]
  RST8_2Dh  (?) get_16bit_from_2030114h ;jap/ori: hl=[20077B4h]
  RST8_2Eh  (?)
  RST8_2Fh PlayCustomSound(a,b)
<B>  Below not for Japanese/Original</B>
  (the renumbered functions can be theoretically used on japanese/original)
  (but, doing so would blow forwards compatibility with japanese/plus)
  RST8_30h (ori: none)      GBA: N/A - Z80: (?)
  RST8_31h (ori: none)      PlayCustomSoundEx(a,b,c)
  RST8_32h (ori: RST8_30h)  BrightnessHalf   ;[4000050h]=00FFh,[4000054h]=0008h
  RST8_33h (ori: RST8_31h)  BrightnessNormal ;[4000050h]=0000h
  RST8_34h (ori: RST8_32h)  N/A (bx lr)
  RST8_35h (ori: RST8_33h)   (?)
  RST8_36h (ori: RST8_34h)  ResetTimer ;[400010Ch]=00000000h, [400010Eh]=A+80h
  RST8_37h (ori: RST8_35h)  GetTimer   ;hl=[400010Ch]
  RST8_38h (ori: none)      GBA: N/A - Z80:  (?)
<B>  Below is undefined/reserved/garbage (values as so in Z80 mode)</B>
  (can be used to tweak jap/ori to start GBA-code from inside of Z80-code)
  (that, after relocating code to 3000xxxh via DMA via IoWrite function)
  RST8_39h (ori: RST8_36h)  bx 0140014h
  RST8_3Ah (ori: RST8_37h)  bx 3E700F0h
  RST8_3Bh (ori: RST8_38h)  bx 3E70000h+1
  RST8_3Ch (ori: RST8_39h)  bx 3E703E6h+1
  RST8_3Dh (ori: RST8_3Ah)  bx 3E703E6h+1
  RST8_3Eh (ori: RST8_3Bh)  bx 3E703E6h+1
  RST8_3Fh (ori: RST8_3Ch)  bx 3E703E6h+1
  40h-FFh  (ori: 3Dh-FFh)   bx ...
</PRE></TD></TR></TBODY></TABLE><BR><B>GBA Functions 03xxh (none such in Z80 
mode)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RSTX_00h Wait8bit  ;for 16bit: RST0_7Dh
  RSTX_01h GetKeyStateSticky()
  RSTX_02h GetKeyStateRaw()
  RSTX_03h  (?)
  RSTX_04h  (?)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereadervpkdecompression></A><FONT size=+2>&nbsp;GBA 
      Cart e-Reader VPK 
Decompression</FONT></TD></TR></TBODY></TABLE><BR><B>vpk_decompress(src,dest)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  collected32bit=80000000h  ;initially empty (endflag in bit31)
  for i=0 to 3, id[i]=read_bits(8), next i, if id[0..3]&lt;&gt;'vpk0' then error
  dest_end=dest+read_bits(32)     ;size of decompressed data (of all strips)
  method=read_bits(8), if method&gt;1 then error
  tree_index=0, read_huffman_tree, disproot=tree_index
  tree_index=tree_index+1, read_huffman_tree, lenroot=tree_index
  ;above stuff is contained only in the first strip. below loop starts at
  ;current location in first strip, and does then continue in further strips.
 decompress_loop:
  if read_bits(1)=0 then                   ;copy one uncompressed data byte,
    [dest]=read_bits(8), dest=dest+1       ;does work without huffman trees
  else
    if disproot=-1 or lenroot=-1 then error  ;compression does require trees
    disp=read_tree(disproot)
    if method=1   ;disp*4 is good for 32bit ARM opcodes
      if disp&gt;2 then disp=disp*4-8 else disp=disp+4*read_tree(disproot)-7
    len=read_tree(lenroot)
    if len=0 or disp&lt;=0 or dest+len-1&gt;dest_end then error ;whoops
    for j=1 to len, [dest]=[dest-disp], dest=dest+1, next j
  if dest&lt;dest_end then decompress_loop
  ret
</PRE></TD></TR></TBODY></TABLE><BR><B>read_bits(num)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  mov  data=0
  for i=1 to num
    shl collected32bit,1   ;move next bit to carry, or set zeroflag if empty
    if zeroflag
      collected32bit=[src+0]*1000000h+[src+1]*10000h+[src+2]*100h+[src+3]
      src=src+4            ;read data in 32bit units, in reversed byte-order
      carryflag=1          ;endbit
      rcl collected32bit,1 ;move bit31 to carry (and endbit to bit0)
    rcl data,1             ;move carry to data
  next i
  ret(data)
</PRE></TD></TR></TBODY></TABLE><BR><B>read_tree(root_index)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  i=root_index
  while node[i].right&lt;&gt;-1  ;loop until reaching data node
    if read_bits(1)=1 then i=node[i].right else i=node[i].left
  i=node[i].left           ;get number of bits
  i=read_bits(i)           ;read that number of bits
  ret(i)                   ;return that value
</PRE></TD></TR></TBODY></TABLE><BR><B>load_huffman_tree</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  stacktop=sp
  if read_bits(1)=1 then tree_index=-1, ret  ;exit (empty)
  node[tree_index].right=-1                  ;indicate data node
  node[tree_index].left=read_bits(8)         ;store data value
  if read_bits(1)=1 then ret                 ;exit (only 1 data node at root)
  push tree_index                     ;save previous (child) node
  tree_index=tree_index+1
  jmp data_injump
 load_loop:
  push tree_index                     ;save previous (child) node
  tree_index=tree_index+1
  if read_bits(1)=1 then parent_node
 data_injump:
  node[tree_index].right=-1           ;indicate data node
  node[tree_index].left=read_bits(8)  ;store data value
  jmp load_loop
 parent_node:
  pop node[tree_index].right          ;store 1st child
  pop node[tree_index].left           ;store 2nd child
  if sp&lt;&gt;stacktop then jmp load_loop
  if read_bits(1)=0 then error        ;end bit (must be 1)
  ret
</PRE></TD></TR></TBODY></TABLE>The best values for the huffman trees that I've 
found are 6,9,12-bit displacements for method 0 (best for NES/Z80 code), and two 
less for method 1, ie. 4,7,10-bit (best for GBA code). And 2,4,10-bit for the 
length values. The smallest value in node 0, and the other values in node 10 and 
11.<BR><BR><B>Notes</B><BR>The decompression works similar to the GBA BIOS'es 
LZ77 decompression function, but without using fixed bit-widths of length=4bit 
and displacement=12bit, instead, the bit-widths are read from huffman trees 
(which can also define fixed bit-widths; if data is located directly in the root 
node).<BR>Unlike the GBA BIOS'es Huffman decompression function, the trees are 
starting with data entries, end are ending with the root entry. The above load 
function deciphers the data, and returns the root index.<BR>With the variable 
bit-widths, the VPK compression rate is quite good, only, it's a pity that the 
length/disp values are zero-based, eg. for 2bit and 4bit lengths, it'd be much 
better to assign 2bit as 2..5, and 4bit as 6..21.<BR><BR><B>Non-VPK</B><BR>The 
e-Reader additionally supports an alternate decompression function, indicated by 
the absence of the "vpk0" ID, which supports compression of increasing 
byte-values, which isn't useful for program code.<BR>Bit15 of the VPK Size value 
seems to disable (de-)compression, the VPK Data field is then containing plain 
uncompressed data.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereadererrorcorrection></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader Error Correction</FONT></TD></TR></TBODY></TABLE><BR>The Error 
Correction Information that is appended at the end of the Block Header &amp; 
Data Fragments consists of standard Reed-Solomon codes, which are also used for 
CD/DVD disks, DSL modems, and digital DVB television signals. That info allows 
to locate and repair a number of invalid data bytes.<BR><BR>Below code shows how 
to create and verify error-info (but not how to do the actual error correction). 
The dtalen,errlen values should be 18h,10h for the Block Header, and 40h,10h for 
Data Fragments; the latter settings might be possible to get changed to other 
values though?<BR><BR><B>append_error_info(data,dtalen,errlen)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reverse_byte_order(data,dtalen)
  zerofill_error_bytes(data,errlen)
  for i=dtalen-1 to errlen  ;loop accross data portion
    z = rev[ data[i] xor data[errlen-1] ] ;
    for j=errlen-1 to 0     ;loop accross error-info portion
    if j=0 then x=00h else x=data[j-1]
      if z&lt;&gt;FFh then
        y=gg[j], if y&lt;&gt;FFh then
          y=y+z, if y&gt;=FFh then y=y-FFh
          x=x xor pow[y]
      data[j]=x
    next j
  next i
  invert_error_bytes(data,errlen)
  reverse_byte_order(data,dtalen)
</PRE></TD></TR></TBODY></TABLE><BR><B>verify_error_info(data,dtalen,errlen)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reverse_byte_order(data,dtalen)
  invert_error_bytes(data,errlen)
  make_rev(data,dtalen)
  for i=78h to 78h+errlen-1
    x=0, z=0
    for j=0 to dtalen-1
      y=data[j]
      if y&lt;&gt;FFh then
        y=y+z, if y&gt;=FFh then y=y-FFh
        x=x xor pow[y]
      z=z+i, if z&gt;=FFh then z=z-FFh
    next j
    if x&lt;&gt;0 then error
  next i
  ;(if errors occured, could correct them now)
  make_pow(data,dtalen)
  invert_error_bytes(data,errlen)
  reverse_byte_order(data,dtalen)
</PRE></TD></TR></TBODY></TABLE><BR><B>make_rev(data,len)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to len-1, data[i]=rev[data[i]], next i
</PRE></TD></TR></TBODY></TABLE><BR><B>make_pow(data,len)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to len-1, data[i]=pow[data[i]], next i
</PRE></TD></TR></TBODY></TABLE><BR><B>invert_error_bytes(data,len)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to len-1, data[i]=data[i] xor FFh, next i
</PRE></TD></TR></TBODY></TABLE><BR><B>zerofill_error_bytes(data,len)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to len-1, data[i]=00h, next i
</PRE></TD></TR></TBODY></TABLE><BR><B>reverse_byte_order(data,len)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to (len-1)/2, x=data[i], data[i]=data[len-i], data[len-i]=x, next i
</PRE></TD></TR></TBODY></TABLE><BR><B>create_pow_and_rev_tables</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  x=01h, pow[FFh]=00h, rev[00h]=FFh
  for i=00h to FEh
    pow[i]=x, rev[x]=i, x=x*2, if x&gt;=100h then x=x xor 187h
  next i
</PRE></TD></TR></TBODY></TABLE><BR><B>create_gg_table</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  gg[0]=pow[78h]
  for i=1 to errlen-1
    gg[i]=01h
    for j=i downto 0
      if j=0 then y=00h else y=gg[j-1]
      x=gg[j], if x&lt;&gt;00h then
        x=rev[x]+78h+i, if x&gt;=FFh then x=x-FFh
        y=y xor pow[x]
      gg[j]=y
    next j
  next i
  make_rev(gg,errlen)
</PRE></TD></TR></TBODY></TABLE>With above value of 78h, and errlen=10h, 
gg[00h..0Fh] will be always:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h,4Bh,EBh,D5h,EFh,4Ch,71h,00h,F4h,00h,71h,4Ch,EFh,D5h,EBh,4Bh
</PRE></TD></TR></TBODY></TABLE>So using a hardcoded table should take up less 
memory than calculating it.<BR><BR><B>Notes</B><BR>The actual error correction 
should be able to fix up to "errlen" errors at known locations (eg. data from 
blocks that haven't been scanned, or whose 5bit-to-4bit conversion had failed 
due to an invalid 5bit value), or up to "errlen/2" errors at unknown locations. 
The corrected data isn't guaranteed to be correct (even if it looks okay to the 
"verify" function), so the Data Header checksums should be checked, 
too.<BR><BR><B>More Info</B><BR>For more info, I've found Reed-Solomon source 
code from Simon Rockliff, and an updated version from Robert Morelos-Zaragoza 
and Hari Thirumoorthy to be useful. For getting started with that source, some 
important relationships &amp; differences are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  pow = alpha_to, but generated as shown above
  rev = index_of, dito
  b0  = 78h
  nn  = dtalen
  kk  = dtalen-errlen
  %nn = MOD FFh (for the ereader that isn't MOD dtalen)
  -1  = FFh
</PRE></TD></TR></TBODY></TABLE>And, the ereader processes data/errinfo 
backwards, starting at the last byte.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartereaderfileformats></A><FONT size=+2>&nbsp;GBA Cart 
      e-Reader File Formats</FONT></TD></TR></TBODY></TABLE><BR><B>.BMP Files 
(homebrew 300 DPI strips)</B><BR>Contains a picture of the whole dotcode strip 
with address bars and sync marks (see Dotcode chapter) in Microsoft's Bitmap 
format. The image is conventionally surrounded by a blank 2-pixel border, 
resulting in a size of 989x44 pixels for long strips. The file should should 
have 1bit color depth. The pixels per meter entry should match the desired 
printing resolution, either 300 DPI or 360 DPI. But, resolution of printer 
hardware is typically specified in inch rather than in meters, so an exact match 
isn't supported by Microsoft. Most homebrew .BMP files contain nonsense 
resolutions like 200 DPI, or 300 dots per meter (ca. 8 DPI).<BR><BR><B>.JPG 
Files (scanned 1200 DPI strips)</B><BR>Same as BMP, but should contain a dotcode 
scanned at 1200 DPI, with correct orientation (the card-edge side at the bottom 
of the image), and containing only the dotcode (not the whole card), so the JPG 
size should be about 3450x155 pixels for long strips.<BR>No$gba currently 
doesn't work with progressive JPGs. Scans with white background can be saved as 
monochrome JPG. Scans with red/yellow background should contain a correct RED 
layer (due to the red LED light source) (the brightness of the green/blue layers 
can be set to zero for better compression).<BR><BR><B>.RAW Files</B><BR>Contains 
the "raw" information from the BMP format, that is, 2-byte block header, 
102-byte data, 2-byte block header, 102-byte data, etc. The data portion is 
interleaved, and includes the full 48-byte data header, titles, vpk compressed 
data, error-info, and unused bytes. RAW files are excluding Address Bars, Sync 
Marks, and 4bit-to-5bit encoding.<BR>Each RAW file contains one or more 
strip(s), so the RAW filesize is either 18*104 bytes (short strip), or 28*104 
bytes (long strip), or a multiple thereof (if it contains more than one strip) 
(although multi-strip games are often stored in separate files for each strip; 
named file1.raw, file2.raw, etc).<BR><BR><B>.BIN Files</B><BR>Filesize should be 
I*30h, with I=1Ch for short strips, and I=2Ch for long strips, or a multiple 
thereof (if it contains more than one strip). Each strip consists of the 48-byte 
Data Header, followed by title(s), and vpk compressed data. Unlike .RAW files, 
.BIN files aren't interleaved, and do not contain Block Headers, nor error-info, 
nor unused bytes (in last block). The files do contain padding bytes to match a 
full strip-size of I*30h.<BR>Caution: Older .BIN files have been using a 
size-reduced 12-byte header (taken from entries 0Dh, 0Ch, 10h-11h, 26h-2Dh of 
the 48-byte Data Header; in that order), that files have never contained more 
than one strip per file, so the filesize should be exactly I*30h-36, the 
size-reduced header doesn't contain a Primary Type entry, so it's everyone's bet 
which Card Type is to be used (hint: the 12-byte headers were based on the 
assumption that Primary Type would be always 01h on Short Strips, and 02h on 
Long Strips).<BR><BR><B>.SAV Files</B><BR>Contains a copy of the e-Reader's 
128Kbyte FLASH memory. With the saved e-Reader application being located in the 
2nd 64K-bank, the data consists of a header with title and gba/nes/z80 format 
info, followed by the vpk compressed data. The FLASH memory does also contain 
e-Reader calibration settings, the remaining 100Kbytes are typically 
FFh-filled.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacartunknowndevices></A><FONT size=+2>&nbsp;GBA Cart Unknown 
      Devices</FONT></TD></TR></TBODY></TABLE><BR><B>GBA Infra-Red Port 
(AGB-006)</B><BR>No info?<BR><BR><B>GBA Wireless Adapter (AGB-015 or 
OXY-004)</B><BR>No info?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbaflashcards></A><FONT size=+2>&nbsp;GBA 
  Flashcards</FONT></TD></TR></TBODY></TABLE><BR>Flashcards are re-writable 
cartridges using FLASH memory, allowing to test even multiboot-incompatible GBA 
software on real hardware, providing a good development environment when used in 
combination with a reasonable software debugger.<BR><BR>The carts can be written 
to from external tools, or directly from GBA programs.<BR>Below are pseudo code 
flowcharts for detect, erase, and write operations.<BR>All flash reads/writes 
are meant to be 16bit (ldrh/strh) memory 
accesses.<BR><BR><B>detect_flashcard:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> configure_flashcard(9E2468Ah,9413h)    ;unlock flash advance cards
 turbo=1, send_command(8000000h,90h)    ;enter ID mode (both chips, if any)
 maker=[8000000h], device=[8000000h+2]
 IF maker=device THEN device=[8000000h+4] ELSE turbo=0
 flashcard_read_mode                    ;exit ID mode
 search (maker+device*10000h) in device_list
 total/erase/write_block_size = list_entry SHL turbo
</PRE></TD></TR></TBODY></TABLE><BR><B>flashcard_erase(dest,len):</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> FOR x=1 to len/erase_block_size
  send_command(dest,20h)        ;erase sector command
  send_command(dest,D0h)        ;confirm erase sector
  dest=dest+erase_block_size
 IF wait_busy=okay THEN NEXT x
 enter_read_mode                ;exit erase/status mode
</PRE></TD></TR></TBODY></TABLE><BR><B>flashcard_write(src,dest,len):</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> siz=write_block_size
 FOR x=1 to len/siz
  IF siz=2 THEN send_command(dest,10h)  ;write halfword command
  IF siz&gt;2 THEN send_command(dest,E8h)  ;write to buffer command
  IF siz&gt;2 THEN send_command(dest,16-1) ;buffer size 16 halfwords (per chip)
  FOR y=1 TO siz/2
   [dest]=[src], dest=dest+2, src=src+2 ;write data to buffer
  NEXT y
  IF siz&gt;2 THEN send_command(dest,D0h)  ;confirm write to buffer
 IF wait_busy=okay THEN NEXT x
 enter_read_mode                        ;exit write/status mode
</PRE></TD></TR></TBODY></TABLE><BR><B>send_command(adr,val):</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> [adr]=val
 IF turbo THEN [adr+2]=val
</PRE></TD></TR></TBODY></TABLE><BR><B>enter_read_mode:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> send_command(8000000h,FFh)     ;exit status mode
 send_command(8000000h,FFh)     ;again maybe more stable (as in jeff's source)
</PRE></TD></TR></TBODY></TABLE><BR><B>flashcard_wait_busy:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> start=time
 REPEAT
  stat=[8000000h] XOR 80h
  IF turbo THEN stat=stat OR ([8000000h+2] XOR 80h)
  IF (stat AND 7Fh)&gt;0 THEN error
  IF (stat AND 80h)=0 THEN ready
  IF time-start&gt;5secs THEN timeout
 UNTIL ready OR error OR timeout
 IF error OR timeout THEN send_command(8000000h,50h)    ;clear status
</PRE></TD></TR></TBODY></TABLE><BR><B>configure_flashcard(adr,val): ;required 
for Flash Advance cards only</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> [930ECA8h]=5354h
 [802468Ah]=1234h, repeated 500 times
 [800ECA8h]=5354h
 [802468Ah]=5354h
 [802468Ah]=5678h, repeated 500 times
 [930ECA8h]=5354h
 [802468Ah]=5354h
 [8ECA800h]=5678h
 [80268A0h]=1234h
 [802468Ah]=ABCDh, repeated 500 times
 [930ECA8h]=5354h
 [adr]=val
</PRE></TD></TR></TBODY></TABLE><BR><B>init_backup: ;no info how to use that 
exactly</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> configure_flashcard(942468Ah,???)
</PRE></TD></TR></TBODY></TABLE><BR><B>device_list: (id code, total/erase/write 
sizes in bytes)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ID Code    Total   Erase  Write  Name
  -??-00DCh      ?       ?      ?  Hudson Cart (???)
  00160089h     4M    128K     32  Intel i28F320J3A (Flash Advance)
  00170089h     8M    128K     32  Intel i28F640J3A (Flash Advance)
  00180089h    16M    128K     32  Intel i28F128J3A (Flash Advance)
  00E200B0h      ?     64K      2  Sharp LH28F320BJE ? (Nintendo)
</PRE></TD></TR></TBODY></TABLE><BR><B>Notes</B><BR>All flashcards should work 
at 4,2 waitstates (power on default), most commercial games change waits to 3,1 
which may work unstable with some/older FA flashcards. Intel FLASH specified to 
have a lifetime of 100,000 erases, and average block erase time 1 second (up to 
5 second in worst cases).<BR>Aside from the main FLASH memory, Flash Advance 
(FA) (aka Visoly) cards additionally contain battery buffered SRAM backup, and 
FLASH backup, and in some cases also EEPROM backup.<BR>Turbo FA cards are 
containing two chips interlaced (at odd/even halfword addresses), allowing to 
write/erase both chips simultaneously, resulting in twice as fast programming 
time.<BR>Standard Nintendo flash carts have to be modified before you can 
actually write to them. This is done by removing resistor R7 and putting it at 
empty location R8.<BR>Mind that write/erase/detect modes output status 
information in ROM area, so that in that modes all GBA program code (and any 
interrupt handlers) must be executed in WRAM, not in ROM.<BR><BR>Thanks to Jeff 
Frohwein for his FAQ and CARTLIB sample in FLGBA at devrs.com<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacheatdevices></A><FONT size=+2>&nbsp;GBA Cheat 
      Devices</FONT></TD></TR></TBODY></TABLE><BR>Codebreaker (US) aka Xploder 
(EUR).<BR>Gameshark (US) aka Action Replay (EUR).<BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacheatcodesgeneralinfo">GBA Cheat 
Codes - General Info</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacheatcodescodebreakerxploder">GBA 
Cheat Codes - Codebreaker/Xploder</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacheatcodesgamesharkactionreplayv1v2">GBA 
Cheat Codes - Gameshark/Action Replay V1/V2</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacheatcodesproactionreplayv3">GBA 
Cheat Codes - Pro Action Replay V3</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacheatcodesgeneralinfo></A><FONT size=+2>&nbsp;GBA Cheat 
      Codes - General Info</FONT></TD></TR></TBODY></TABLE><BR>Cheat devices are 
external adapters, connected between the GBA and the game cartridge. The devices 
include a BIOS ROM which is, among others, used to prompt the user to enter 
cheat codes.<BR>These codes are used to patch specified memory locations for a 
certain GBA game, allowing the user to gain goodies such like Infinite sex, 255 
Cigarettes, etc.<BR><BR><B>ROM and RAM Patches</B><BR>For ROM Patches, the 
device watches the address bus, if it matches a specified address then it 
outputs a patched value to the data bus, that mechanism is implemented by 
hardware, aside from the Hook Enable Code some devices also allow a limited 
number of cheats to use ROM patches.<BR>Most cheat codes are RAM patches, each 
time when the hook procedure is executed it will process all codes and overwrite 
the specified addresses in RAM (or VRAM or I/O area) by the desired 
values.<BR><BR><B>Enable Codes (Must Be On)</B><BR>Enable codes usually consist 
of the Game ID, Hook Address, and eventually a third code used to encrypt all 
following codes. The Game ID is used to confirm that the correct cartridge is 
inserted, just a verification, though the device may insist on the ID 
code.<BR>The Hook Address specifies an address in cartridge ROM, and should 
point to an opcode which is executed several times per second (eg. once per 
frame, many codes place the hook in the joypad handler). At the hook address, 
the device redirects to its own BIOS, processes the RAM patches, and does then 
return control to the game cartridge.<BR>Note: The hook address should not point 
to opcodes with relative addressing (eg. B, BL, LDR Rd,=Imm, ADD Rd,=Imm opcodes 
- which are all relative to PC program counter 
register).<BR><BR><B>Alignment</B><BR>Addresses for 16bit or 32bit values should 
be properly aligned.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacheatcodescodebreakerxploder></A><FONT size=+2>&nbsp;GBA 
      Cheat Codes - 
Codebreaker/Xploder</FONT></TD></TR></TBODY></TABLE><BR><B>Codebreaker 
Codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0000xxxx 000y  Enable Code 1 - Game ID
  1aaaaaaa 000z  Enable Code 2 - Hook Address
  2aaaaaaa yyyy  [aaaaaaa]=[aaaaaaa] OR yyyy
  3aaaaaaa 00yy  [aaaaaaa]=yy
  4aaaaaaa yyyy  [aaaaaaa+0..(cccc-1)*ssss]=yyyy+0..(cccc-1)*ssss
  iiiicccc ssss  parameters for above code
  5aaaaaaa cccc  [aaaaaaa+0..(cccc-1)]=11,22,33,44,etc.
  11223344 5566  parameter bytes 1..6 for above code (example)
  77880000 0000  parameter bytes 7..8 for above code (padded with zero)
  6aaaaaaa yyyy  [aaaaaaa]=[aaaaaaa] AND yyyy
  7aaaaaaa yyyy  IF [aaaaaaa]=yyyy THEN (next code)
  8aaaaaaa yyyy  [aaaaaaa]=yyyy
  9xyyxxxx xxxx  Enable Code 0 - Encrypt all following codes (optional)
  Aaaaaaaa yyyy  IF [aaaaaaa]&lt;&gt;yyyy THEN (next code)
  Baaaaaaa yyyy  IF [aaaaaaa]&gt;yyyy THEN (next code) (signed comparison)
  Caaaaaaa yyyy  IF [aaaaaaa]&lt;yyyy THEN (next code) (signed comparison)
  D0000020 yyyy  IF [joypad] AND yyyy = 0 THEN (next code)
  Eaaaaaaa yyyy  [aaaaaaa]=[aaaaaaa]+yyyy
  Faaaaaaa yyyy  IF [aaaaaaa] AND yyyy THEN (next code)
</PRE></TD></TR></TBODY></TABLE><BR><B>Codebreaker Enable Codes</B><BR>Hook 
Address 'aaaaaaa' is a 25bit offset in ROM-image (0-1FFFFFFh).<BR>Flag byte 'y' 
(usually 0Ah), Bit1=Disable IRQs, Bit3=CRC Exists.<BR>Code Handler Store Address 
'z' (0-7, usually 7) (8000100h+z*400000h).<BR>Checksum 'xxxx' for first 64Kbytes 
of cartridge (no$gba pads by FFh if ROM is smaller than 64K). Calculated, by 
using unsigned 16bit values, as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  crc=FFFFh
  for i=0 to FFFFh
   x=byte[i] xor (crc/100h)
   x=x xor (x/10h)
   crc=(crc*100h) xor (x*1001h) xor (x*20h)
  next i
</PRE></TD></TR></TBODY></TABLE><BR><B>Codebreaker 
Encryption</B><BR>codebreaker_change_encryption:<BR>Encryption can be 
(optionally) activated by code "9xyyxxxx xxxx",<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to 2Fh, swaplist[i]=i, next i
  randomizer = 1111h xor byte[code+4]                              ;LSB value
  for i=0 to 4Fh
    exchange swaplist[random MOD 30h] with swaplist[random MOD 30h]
  next i
  halfword[seedlist+0] = halfword[code+0]                          ;LSW address
  randomizer = 4EFAD1C3h
  for i=0 to byte[code+3]-91h, randomizer=random, next i           ;MSB address
  word[seedlist+2]=random, halfword[seedlist+6]=random
  randomizer = F254h xor byte[code+5]                              ;MSB value
  for i=0 to byte[code+5]-01h, randomizer=random, next i           ;MSB value
  word[seedlist+8]=random, halfword[seedlist+12]=random
  ;note: byte[code+2] = don't care
  ret
</PRE></TD></TR></TBODY></TABLE>The above random function works like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  randomizer=randomizer*41C64E6Dh+3039h, x=(randomizer SHL 14 AND C0000000h)
  randomizer=randomizer*41C64E6Dh+3039h, x=(randomizer SHR 1  AND 3FFF8000h)+x
  randomizer=randomizer*41C64E6Dh+3039h, x=(randomizer SHR 16 AND 00007FFFh)+x
  return(x)
</PRE></TD></TR></TBODY></TABLE>Once when encryption is activated, all following 
codes are decrypted like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=2Fh to 0
    j=swaplist[i]
    bitno1=(i AND 7), index1=xlatlist[i/8]
    bitno2=(j AND 7), index2=xlatlist[j/8]
    exchange [code+index1].bitno1 with [code+index2].bitno2
  next i
  word[code+0] = word[code+0] xor word[seedlist+8]
  i = (byte[code+3]*1010000h + byte[code+0]*100h + byte[code+5])
  i = (halfword[code+1]*10001h) xor (word[seedlist+2]) xor i
  i = (byte[seedlist+0]*1010101h) xor (byte[seedlist+1]*1000000h) xor i
  j = (byte[code+5] + (byte[code+0] xor byte[code+4])*100h)
  j = (byte[seedlist+0]*101h) xor halfword[seedlist+6] xor j
  word[code+0] = i, halfword[code+4] = j
</PRE></TD></TR></TBODY></TABLE>The above xlatlist is fixed: xlatlist[0..5] = 
3,2,1,0,5,4<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacheatcodesgamesharkactionreplayv1v2></A><FONT 
      size=+2>&nbsp;GBA Cheat Codes - Gameshark/Action Replay 
  V1/V2</FONT></TD></TR></TBODY></TABLE><BR><B>Gameshark RAW Codes (These codes 
must be encrypted before using them)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0aaaaaaa 000000xx  [aaaaaaa]=xx
  1aaaaaaa 0000xxxx  [aaaaaaa]=xxxx
  2aaaaaaa xxxxxxxx  [aaaaaaa]=xxxxxxxx
  3000cccc xxxxxxxx  write xxxxxxxx to (cccc-1) addresses (list in next codes)
  aaaaaaaa aaaaaaaa  parameter for above code, containing two addresses each
  aaaaaaaa 00000000  last parameter for above, zero-padded if only one address
  60aaaaaa y000xxxx  [8000000h+aaaaaa*2]=xxxx (ROM Patch)
  8a1aaaaa 000000xx  IF GS_Button_Down THEN [a0aaaaa]=xx
  8a2aaaaa 0000xxxx  IF GS_Button_Down THEN [a0aaaaa]=xxxx
  80F00000 0000xxxx  IF GS_Button_Down THEN slowdown xxxx * ??? cycles per hook
  Daaaaaaa 0000xxxx  IF [aaaaaaa]=xxxx THEN (next code)
  E0zzxxxx 0aaaaaaa  IF [aaaaaaa]=xxxx THEN (next 'zz' codes)
  Faaaaaaa 00000x0y  Enable Code - Hook Routine
  xxxxxxxx 001DC0DE  Enable Code - Game Code ID (value at [0ACh] in cartridge)
  DEADFACE 0000xxyy  Change Encryption Seeds
</PRE></TD></TR></TBODY></TABLE><BR><B>Enable Code - Hook Routine</B><BR>Hook 
Address 'aaaaaaa' is a 28bit ROM address (8FFFFFFh-9FFFFFFh).<BR>Used to insert 
the GS code handler routine where it will be executed at<BR>least 20 times per 
second. Without this code, GSA can not write to RAM.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> y=1 - Executes code handler without backing up the LR register.
 y=2 - Executes code handler and backs up the LR register.
 y=3 - Replaces a 32-bit pointer used for long-branches.
 x=0 - Must turn GSA off before loading game.
 x=1 - Must not do that.
</PRE></TD></TR></TBODY></TABLE><BR><B>ROM Patch</B><BR>This type allows GSA to 
intercept ROM reads and returns the value xxxx.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> y=0 wait for the code handler to enable the patch
 y=1 patch is enabled before the game starts
 y=2 unknown ???
</PRE></TD></TR></TBODY></TABLE>Note: V1/V2 hardware can only have up to 1 
user-defined rom patch max. V3 can have up to 4. Some enable code types can 
shorten the amount of user-defined rom patches available.<BR><BR><B>Gameshark 
Encryption</B><BR>A=Left half, and V=Right half of code.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  FOR I=1 TO 32
    A=A + (V*16+S0) XOR (V+I*9E3779B9h) XOR (V/32+S1)
    V=V + (A*16+S2) XOR (A+I*9E3779B9h) XOR (A/32+S3)
  NEXT I
</PRE></TD></TR></TBODY></TABLE>Upon startup, the initial encryption seeds 
are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  S0=09F4FBBDh S1=9681884Ah S2=352027E9h S3=F3DEE5A7h
</PRE></TD></TR></TBODY></TABLE>Upon DEADFACE 0000xxyy, the S0..S3 seeds are 
changed like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  FOR y=0 TO 3
   FOR x=0 TO 3
    z = T1[(xx+x) AND FFh] + T2[(yy+y) AND FFh]
    Sy = Sy*100h + (z AND FFh)
   NEXT x
  NEXT y
</PRE></TD></TR></TBODY></TABLE>All calculations truncated to unsigned 32bit 
integer values.<BR>T1 and T2 are translation tables contained in the gameshark 
cartridge.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbacheatcodesproactionreplayv3></A><FONT size=+2>&nbsp;GBA 
      Cheat Codes - Pro Action Replay V3</FONT></TD></TR></TBODY></TABLE><BR><B>Pro 
Action Replay V3 - RAW Codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  C4aaaaaa 0000yyyy  Enable Code - Hook Routine at [8aaaaaa]
  xxxxxxxx 001DC0DE  Enable Code - ID Code [080000AC]
  DEADFACE 0000xxxx  Enable Code - Change Encryption Seeds
  00aaaaaa xxxxxxyy  [a0aaaaa..a0aaaaa+xxxxxx]=yy
  02aaaaaa xxxxyyyy  [a0aaaaa..a0aaaaa+xxxx*2]=yyyy
  04aaaaaa yyyyyyyy  [a0aaaaa]=yyyyyyyy
  40aaaaaa xxxxxxyy  [ [a0aaaaa] + xxxxxx ]=yy   (Indirect)
  42aaaaaa xxxxyyyy  [ [a0aaaaa] + xxxx*2 ]=yyyy (Indirect)
  44aaaaaa yyyyyyyy  [ [a0aaaaa] ]=yyyyyyyy      (Indirect)
  80aaaaaa 000000yy  [a0aaaaa]=[a0aaaaa]+yy
  82aaaaaa 0000yyyy  [a0aaaaa]=[a0aaaaa]+yyyy
  84aaaaaa yyyyyyyy  [a0aaaaa]=[a0aaaaa]+yyyyyyyy
  C6aaaaaa 0000yyyy  [4aaaaaa]=yyyy              (I/O Area)
  C7aaaaaa yyyyyyyy  [4aaaaaa]=yyyyyyyy          (I/O Area)
  iiaaaaaa yyyyyyyy  IF [a0aaaaa] &lt;cond&gt; &lt;value&gt; THEN &lt;action&gt;
  00000000 60000000  ELSE (?)
  00000000 40000000  ENDIF (?)
  00000000 0800xx00  AR Slowdown : loops the AR xx times
  00000000 00000000  End of the code list
  00000000 10aaaaaa 000000zz 00000000  IF AR_BUTTON THEN [a0aaaaa]=zz
  00000000 12aaaaaa 0000zzzz 00000000  IF AR_BUTTON THEN [a0aaaaa]=zzzz
  00000000 14aaaaaa zzzzzzzz 00000000  IF AR_BUTTON THEN [a0aaaaa]=zzzzzzzz
  00000000 18aaaaaa 0000zzzz 00000000  [8000000+aaaaaa*2]=zzzz  (ROM Patch 1)
  00000000 1Aaaaaaa 0000zzzz 00000000  [8000000+aaaaaa*2]=zzzz  (ROM Patch 2)
  00000000 1Caaaaaa 0000zzzz 00000000  [8000000+aaaaaa*2]=zzzz  (ROM Patch 3)
  00000000 1Eaaaaaa 0000zzzz 00000000  [8000000+aaaaaa*2]=zzzz  (ROM Patch 4)
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000 80aaaaaa 000000yy ssccssss  repeat cc times [a0aaaaa]=yy
   (with yy=yy+ss, a0aaaaa=a0aaaaa+ssss after each step)
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000 82aaaaaa 0000yyyy ssccssss  repeat cc times [a0aaaaa]=yyyy
   (with yyyy=yyyy+ss, a0aaaaa=a0aaaaa+ssss*2 after each step)
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000 84aaaaaa yyyyyyyy ssccssss  repeat cc times [a0aaaaa]=yyyyyyyy
   (with yyyy=yyyy+ss, a0aaaaa=a0aaaaa+ssss*4 after each step)
</PRE></TD></TR></TBODY></TABLE><BR>Warning: There is a bug on the real AR (v2 
upgraded to v3, and maybe on real v3) with the 32bit Increment Slide code. You 
HAVE to add a code (best choice is 80000000 00000000 : add 0 to value at address 
0) right after it, else the AR will erase the 2 last 8 digits lines of the 32 
Bits Inc. Slide code when you enter it !!!<BR><BR>Final Notes<BR>The 'turn off 
all codes' makes an infinite loop (that can't be broken, unless the condition 
becomes True). - How? By Interrupt? Huh?<BR>ROM Patch1 works on real V3 and, on 
V1/V2 upgraded to V3.<BR>ROM Patch2,3,4 work on real V3 hardware 
only.<BR><BR><B>Pro Action Replay V3 Conditional Codes - iiaaaaaa 
yyyyyyyy</B><BR>The 'ii' is composed of &lt;cond&gt; + &lt;value&gt; + 
&lt;action&gt;.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  &lt;cond&gt;           &lt;value&gt;            &lt;action&gt;
  08 Equal =       00 8bit zz         00 execute next code
  10 Not equal &lt;&gt;  02 16bit zzzz      40 execute next two codes
  18 Signed &lt;      04 32bit zzzzzzzz  80 execute all following
  20 Signed &gt;      06 (always false)     codes until ELSE or ENDIF
  28 Unsigned &lt;                       C0 normal ELSE turn off all codes
  30 Unsigned &gt;
  38 Logical AND
</PRE></TD></TR></TBODY></TABLE>For example, ii=18h+02h+40h=5Ah, produces IF 
[a0aaaaa]&lt;zzzz THEN next 2 codes.<BR><BR>Always... Codes<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  For the "Always..." codes:
  - XXXXXXXX can be any authorised address except 00000000 (eg. use 02000000).
  - ZZZZZZZZ can be anything.
  - The "y" in the code data must be in the [1-7] range (which means not 0).
  typ=y,sub=0,siz=3   Always skip next line.
  typ=y,sub=1,siz=3   Always skip next 2 lines.
  typ=y,sub=2,siz=3   Always Stops executing all the codes below.
  typ=y,sub=3,siz=3   Always turn off all codes.
</PRE></TD></TR></TBODY></TABLE><BR><B>Code Format (ttaaaaaa xxxxyyzz)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> adr mask = 003FFFFF
 n/a mask = 00C00000 ;not used
 xtr mask = 01000000 ;used only by I/O write, and MSB of Hook
 siz mask = 06000000
 typ mask = 38000000 ;0=normal, other=conditional
 sub mask = C0000000
</PRE></TD></TR></TBODY></TABLE><BR><B>Pro Action Replay V3 
Encryption</B><BR>Works exactly as for Gameshark Encryption, but with different 
initial seeds,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  S0=7AA9648Fh S1=7FAE6994h S2=C0EFAAD5h S3=42712C57h
</PRE></TD></TR></TBODY></TABLE>And, the T1 and T2 translation tables are 
different, too.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=gbagameboyplayer></A><FONT size=+2>&nbsp;GBA Gameboy 
      Player</FONT></TD></TR></TBODY></TABLE><BR>The Gameboy Player is an "adapter" 
for the Gamecube console. It's basicly is a GBA in a black box without LCD 
screen and without buttons, connected to an expansion port at the bottom of the 
Gamecube. The Gamecube is then capturing the GBA video output (and passing it to 
the television set), and in the other direction, passing the Gamecube joypad 
input to the GBA inputs.<BR><BR><B>Unlocking and Detecting Gameboy Player 
Functions</B><BR>Both unlocking and detection requires to display the 240x160 
pixel Gameboy Player logo (44 colors) for a number of frames... maybe at least 
3-4 frames? not sure if it checks the color of the logo... so maybe it can be 
hidden by using dark gray on black background?<BR>While displaying this logo, 
the joypad data will switch between values 03FFh (2 frames duration) and 030Fh 
(1 frame duration). The latter value (left, right, up, down all pressed) 
indicates that it's a Gameboy Player.<BR><BR><B>Palette</B><BR>Knowing Nintendo, 
they've probably not reproduced the blurred GBA colors (?), so the games won't 
look as desired on the TV screen. Unless the game does detect the Gameboy 
Player, and adjust the colors accordingly by 
software.<BR><BR><B>Rumble</B><BR>The only known existing special function is 
the joypad rumble function, still, it's unknown HOW it works exactly - it's 
somehow (?) controlled by sending data through the serial port (the normal GBA 
port, even though it also has the connectors).<BR><BR><B>Note</B><BR>If it's 
having a similar range of functions as the 8bit Super Gameboy, then the Gameboy 
Player might be also able to access analogue joypad input, and to access other 
features of the Gamecube hardware, up to possibly executing code on the Gamecube 
CPU...?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosfunctions></A><FONT size=+2>&nbsp;BIOS 
  Functions</FONT></TD></TR></TBODY></TABLE><BR>The GBA BIOS includes several 
System Call Functions which can be accessed by SWI instructions. Incoming 
parameters are usually passed through registers R0,R1,R2,R3. Outgoing registers 
R0,R1,R3 are typically containing either garbage, or return value(s). All other 
registers (R2,R4-R14) are kept unchanged.<BR><BR><B>Caution</B><BR>When invoking 
SWIs from inside of ARM state specify SWI NN*10000h, instead of SWI NN as in 
THUMB state.<BR><BR><B>Overview</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosfunctionsummary">BIOS Function 
Summary</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosdifferencesbetweengbaandndsfunctions">BIOS 
Differences between GBA and NDS functions</A><BR><BR><B>All Functions 
Described</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosarithmeticfunctions">BIOS 
Arithmetic Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosrotationscalingfunctions">BIOS 
Rotation/Scaling Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosdecompressionfunctions">BIOS 
Decompression Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosmemorycopy">BIOS Memory 
Copy</A><BR><A href="http://nocash.emubase.de/gbatek.htm#bioshaltfunctions">BIOS 
Halt Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosresetfunctions">BIOS Reset 
Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosmiscfunctions">BIOS Misc 
Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosmultibootsinglegamepak">BIOS Multi 
Boot (Single Game Pak)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biossoundfunctions">BIOS Sound 
Functions</A><BR><BR><B>How BIOS Processes SWIs</B><BR>SWIs can be called from 
both within THUMB and ARM mode. In ARM mode, only the upper 8bit of the 24bit 
comment field are interpreted.<BR>Each time when calling a BIOS function 4 words 
(SPSR, R11, R12, R14) are saved on Supervisor stack (_svc). Once it has saved 
that data, the SWI handler switches into System mode, so that all further stack 
operations are using user stack.<BR>In some cases the BIOS may allow interrupts 
to be executed from inside of the SWI procedure. If so, and if the interrupt 
handler calls further SWIs, then care should be taken that the Supervisor Stack 
does not overflow.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosfunctionsummary></A><FONT size=+2>&nbsp;BIOS Function 
      Summary</FONT></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  GBA  NDS7 NDS9 Function</B>
  00h  00h  00h  SoftReset
  01h  -    -    RegisterRamReset
  02h  06h  06h  Halt
  03h  07h  -    Stop/Sleep
  04h  04h  04h  IntrWait
  05h  05h  05h  VBlankIntrWait
  06h  09h  09h  Div
  07h  -    -    DivArm
  08h  0Dh  0Dh  Sqrt
  09h  -    -    ArcTan
  0Ah  -    -    ArcTan2
  0Bh  0Bh  0Bh  CpuSet
  0Ch  0Ch  0Ch  CpuFastSet
  0Dh  -    -    GetBiosChecksum
  0Eh  -    -    BgAffineSet
  0Fh  -    -    ObjAffineSet
  10h  10h  10h  BitUnPack
  11h  11h  11h  LZ77UnCompWram
  12h  12h  12h  LZ77UnCompVram
  13h  13h  13h  HuffUnComp
  14h  14h  14h  RLUnCompWram
  15h  15h  15h  RLUnCompVram
  16h  -    16h  Diff8bitUnFilterWram
  17h  -    -    Diff8bitUnFilterVram
  18h  -    18h  Diff16bitUnFilter
  19h  08h  -    SoundBias
  1Ah  -    -    SoundDriverInit
  1Bh  -    -    SoundDriverMode
  1Ch  -    -    SoundDriverMain
  1Dh  -    -    SoundDriverVSync
  1Eh  -    -    SoundChannelClear
  1Fh  -    -    MidiKey2Freq
  20h  -    -    SoundWhatever0
  21h  -    -    SoundWhatever1
  22h  -    -    SoundWhatever2
  23h  -    -    SoundWhatever3
  24h  -    -    SoundWhatever4
  25h  -    -    MultiBoot
  26h  -    -    HardReset
  27h  1Fh  -    CustomHalt
  28h  -    -    SoundDriverVSyncOff
  29h  -    -    SoundDriverVSyncOn
  2Ah  -    -    SoundGetJumpList
  -    03h  03h  WaitByLoop
  -    0Eh  0Eh  GetCRC16
  -    0Fh  0Fh  IsDebugger
  -    1Ah  -    GetSineTable
  -    1Bh  -    GetPitchTable
  -    1Ch  -    GetVolumeTable
  -    1Dh  -    GetBootProcs
  -    -    1Fh  CustomPost
</PRE></TD></TR></TBODY></TABLE>The BIOS SWI handler does not perform any range 
checks, so calling GBA SWI 2Bh-FFh or NDS SWI 20h-FFh will blindly jump to 
garbage addresses.<BR>Also, NDS7 SWI 01h, 02h, 0Ah, 16h-19h, 1Eh, and NDS9 SWI 
01h, 02h, 07h, 08h, 0Ah, 17h, 19h-1Eh will jump to zero (ie. to the NDS7 reset 
vector, or to NDS9 unused (usually PU-locked ITCM) memory, which will be both 
redirected to the debug handler, if any).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosdifferencesbetweengbaandndsfunctions></A><FONT 
      size=+2>&nbsp;BIOS Differences between GBA and NDS 
  functions</FONT></TD></TR></TBODY></TABLE><BR><B>Differences between GBA and NDS 
BIOS functions</B><BR>- SoftReset uses different addresses<BR>- SWI numbers for 
Halt, Stop/Sleep, Div, Sqrt have changed<BR>- Halt destroys r0 on NDS9, IntrWait 
bugged on NDS9<BR>- CpuFastSet allows 4-byte blocks (nice), but...<BR>- 
CpuFastSet works very SLOW because of a programming bug (uncool)<BR>- 
LZ77UnCompVram, HuffUnComp, RLUnCompVram use callbacks<BR>- SoundBias uses new 
delay parameter<BR>And, a number of GBA functions have been removed, and some 
new NDS functions have been added, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosfunctionsummary">BIOS Function 
Summary</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosarithmeticfunctions></A><FONT size=+2>&nbsp;BIOS 
      Arithmetic 
Functions</FONT></TD></TR></TBODY></TABLE><BR>Div<BR>DivArm<BR>Sqrt<BR>ArcTan<BR>ArcTan2<BR><BR><B>SWI 
06h (GBA) or SWI 09h (NDS7/NDS9) - Div</B><BR>Signed Division, r0/r1.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  signed 32bit Number
  r1  signed 32bit Denom
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Number DIV Denom ;signed
  r1  Number MOD Denom ;signed
  r3  ABS (Number DIV Denom) ;unsigned
</PRE></TD></TR></TBODY></TABLE>For example, incoming -1234, 10 should return 
-123, -4, +123.<BR>The function usually gets caught in an endless loop upon 
division by zero.<BR>Note: The NDS9 additionally supports hardware division, by 
math coprocessor, accessed via I/O Ports, however, the SWI function is a raw 
software division.<BR><BR><B>SWI 07h (GBA) - DivArm</B><BR>Same as above (SWI 
06h Div), but incoming parameters are exchanged, r1/r0 (r0=Denom, r1=number). 
For compatibility with ARM's library. Slightly slower (3 clock cycles) than SWI 
06h.<BR><BR><B>SWI 08h (GBA) or SWI 0Dh (NDS7/NDS9) - Sqrt</B><BR>Calculate 
square root.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   unsigned 32bit number
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   unsigned 16bit number
</PRE></TD></TR></TBODY></TABLE>The result is an integer value, so Sqrt(2) would 
return 1, to avoid this inaccuracy, shift left incoming number by 2*N as much as 
possible (the result is then shifted left by 1*N). Ie. Sqrt(2 shl 30) would 
return 1.41421 shl 15.<BR>Note: The NDS9 additionally supports hardware square 
root calculation, by math coprocessor, accessed via I/O Ports, however, the SWI 
function is a raw software calculation.<BR><BR><B>SWI 09h (GBA) - 
ArcTan</B><BR>Calculates the arc tangent.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   Tan, 16bit (1bit sign, 1bit integral part, 14bit decimal part)
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   "-PI/2&lt;THETA/&lt;PI/2" in a range of C000h-4000h.
</PRE></TD></TR></TBODY></TABLE>Note: there is a problem in accuracy with 
"THETA&lt;-PI/4, PI/4&lt;THETA".<BR><BR><B>SWI 0Ah (GBA) - 
ArcTan2</B><BR>Calculates the arc tangent after correction processing.<BR>Use 
this in normal situations.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   X, 16bit (1bit sign, 1bit integral part, 14bit decimal part)
  r1   Y, 16bit (1bit sign, 1bit integral part, 14bit decimal part)
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   0000h-FFFFh for 0&lt;=THETA&lt;2PI.
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosrotationscalingfunctions></A><FONT size=+2>&nbsp;BIOS 
      Rotation/Scaling 
Functions</FONT></TD></TR></TBODY></TABLE><BR>BgAffineSet<BR>ObjAffineSet<BR><BR><B>SWI 
0Eh (GBA) - BgAffineSet</B><BR>Used to calculate BG Rotation/Scaling 
parameters.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   Pointer to Source Data Field with entries as follows:
        s32  Original data's center X coordinate (8bit fractional portion)
        s32  Original data's center Y coordinate (8bit fractional portion)
        s16  Display's center X coordinate
        s16  Display's center Y coordinate
        s16  Scaling ratio in X direction (8bit fractional portion)
        s16  Scaling ratio in Y direction (8bit fractional portion)
        u16  Angle of rotation (8bit fractional portion) Effective Range 0-FFFF
  r1   Pointer to Destination Data Field with entries as follows:
        s16  Difference in X coordinate along same line
        s16  Difference in X coordinate along next line
        s16  Difference in Y coordinate along same line
        s16  Difference in Y coordinate along next line
        s32  Start X coordinate
        s32  Start Y coordinate
  r2   Number of Calculations
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR><B>SWI 0Fh (GBA) - ObjAffineSet</B><BR>Calculates 
and sets the OBJ's affine parameters from the scaling ratio and angle of 
rotation.<BR>The affine parameters are calculated from the parameters set in 
Srcp.<BR>The four affine parameters are set every Offset bytes, starting from 
the Destp address.<BR>If the Offset value is 2, the parameters are stored 
contiguously. If the value is 8, they match the structure of OAM.<BR>When Srcp 
is arrayed, the calculation can be performed continuously by specifying Num.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   Source Address, pointing to data structure as such:
        s16  Scaling ratio in X direction (8bit fractional portion)
        s16  Scaling ratio in Y direction (8bit fractional portion)
        u16  Angle of rotation (8bit fractional portion) Effective Range 0-FFFF
  r1   Destination Address, pointing to data structure as such:
        s16  Difference in X coordinate along same line
        s16  Difference in X coordinate along next line
        s16  Difference in Y coordinate along same line
        s16  Difference in Y coordinate along next line
  r2   Number of calculations
  r3   Offset in bytes for parameter addresses (2=continuous, 8=OAM)
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR>For both Bg- and ObjAffineSet, Rotation angles are 
specified as 0-FFFFh (covering a range of 360 degrees), however, the GBA BIOS 
recurses only the upper 8bit; the lower 8bit may contain a fractional portion, 
but it is ignored by the BIOS.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosdecompressionfunctions></A><FONT size=+2>&nbsp;BIOS 
      Decompression 
Functions</FONT></TD></TR></TBODY></TABLE><BR>BitUnPack<BR>Diff8bitUnFilterWram<BR>Diff8bitUnFilterVram<BR>Diff16bitUnFilter<BR>HuffUnComp<BR>LZ77UnCompWram<BR>LZ77UnCompVram<BR>RLUnCompVram<BR>RLUnCompWram<BR><BR><B>SWI 
10h (GBA/NDS7/NDS9) - BitUnPack</B><BR>Used to increase the color depth of 
bitmaps or tile data. For example, to convert a 1bit monochrome font into 4bit 
or 8bit GBA tiles. The Unpack Info is specified separately, allowing to convert 
the same source data into different formats.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Source Address      (no alignment required)
  r1  Destination Address (must be 32bit-word aligned)
  r2  Pointer to UnPack information:
       16bit  Length of Source Data in bytes     (0-FFFFh)
       8bit   Width of Source Units in bits      (only 1,2,4,8 supported)
       8bit   Width of Destination Units in bits (only 1,2,4,8,16,32 supported)
       32bit  Data Offset (Bit 0-30), and Zero Data Flag (Bit 31)
      The Data Offset is always added to all non-zero source units.
      If the Zero Data Flag was set, it is also added to zero units.
</PRE></TD></TR></TBODY></TABLE>Data is written in 32bit units, Destination can 
be Wram or Vram. The size of unpacked data must be a multiple of 4 bytes. The 
width of source units (plus the offset) should not exceed the destination 
width.<BR>Return: No return value, Data written to destination 
address.<BR><BR><B>SWI 16h (GBA/NDS9) - Diff8bitUnFilterWram</B><BR><B>SWI 17h 
(GBA) - Diff8bitUnFilterVram</B><BR><B>SWI 18h (GBA/NDS9) - 
Diff16bitUnFilter</B><BR>These aren't actually real decompression functions, 
destination data will have exactly the same size as source data. However, assume 
a bitmap or wave form to contain a stream of increasing numbers such like 
10..19, the filtered/unfiltered data would be:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  unfiltered:   10  11  12  13  14  15  16  17  18  19
  filtered:     10  +1  +1  +1  +1  +1  +1  +1  +1  +1
</PRE></TD></TR></TBODY></TABLE>In this case using filtered data (combined with 
actual compression algorithms) will obviously produce better compression 
results.<BR>Data units may be either 8bit or 16bit used with Diff8bit or 
Diff16bit functions respectively. The 8bitVram function allows to write to VRAM 
directly (which uses 16bit data bus) by writing two 8bit values at once, the 
downside is that it is eventually slower as the 8bitWram function.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Source address (must be aligned by 4) pointing to data as follows:
       Data Header (32bit)
         Bit 0-3   Data size (must be 1 for Diff8bit, 2 for Diff16bit)
         Bit 4-7   Type (must be 8 for DiffFiltered)
         Bit 8-31  24bit size after decompression
       Data Units (each 8bit or 16bit depending on used SWI function)
         Data0          ;original data
         Data1-Data0    ;difference data
         Data2-Data1    ;...
         Data3-Data2
         ...
  r1  Destination address
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR><B>SWI 13h (GBA/NDS7/NDS9) - HuffUnComp (NDS: with 
Callback)</B><BR>The decoder starts in root node, the separate bits in the 
bitstream specify if the next node is node0 or node1, if that node is a data 
node, then the data is stored in memory, and the decoder is reset to the root 
node. The most often used data should be as close to the root node as possible. 
For example, the 4-byte string "Huff" could be compressed to 6 bits: 10-11-0-0, 
with root.0 pointing directly to data "f", and root.1 pointing to a child node, 
whose nodes point to data "H" and data "u".<BR>Data is written in units of 
32bits, if the size of the compressed data is not a multiple of 4, please adjust 
it as much as possible by padding with 0.<BR>Align the source address to a 4Byte 
boundary.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Source Address, aligned by 4, pointing to:
       Data Header (32bit)
         Bit0-3   Data size in bit units (normally 4 or 8)
         Bit4-7   Compressed type (must be 2 for Huffman)
         Bit8-31  24bit size of decompressed data in bytes
       Tree Size (8bit)
         Bit0-7   Size of Tree Table/2-1 (ie. Offset to Compressed Bitstream)
       Tree Table (list of 8bit nodes, starting with the root node)
        Root Node and Non-Data-Child Nodes are:
         Bit0-5   Offset to next child node,
                  Next child node0 is at (CurrentAddr AND NOT 1)+Offset*2+2
                  Next child node1 is at (CurrentAddr AND NOT 1)+Offset*2+2+1
         Bit6     Node1 End Flag (1=Next child node is data)
         Bit7     Node0 End Flag (1=Next child node is data)
        Data nodes are (when End Flag was set in parent node):
         Bit0-7   Data (upper bits should be zero if Data Size is less than 8)
       Compressed Bitstream (stored in units of 32bits)
         Bit0-31  Node Bits (Bit31=First Bit)  (0=Node0, 1=Node1)
  r1  Destination Address
  r2  Callback parameter (NDS SWI 13h only, see Callback notes below)
  r3  Callback structure (NDS SWI 13h only, see Callback notes below)
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> lea  ebx,[esi+1]               ;\
 mov  @@root,ebx                ; init source pointers
 movzx eax,byte ptr ds:[esi]    ;
 lea  esi,[esi+eax*2+2]         ;/
 mov  edx,80000000h ;stop-bit
</PRE></TD></TR></TBODY></TABLE>@@data_lop:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> mov  dword ptr [@@data],0
 mov  byte ptr [@@cnt],-32
 ;--- bit loop ---
</PRE></TD></TR></TBODY></TABLE>@@lop:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> mov  al,byte ptr ds:[ebx]      ;\
 mov  ch,al         ;bit6,bit7  ; get node entry (offset/flags)
 and  eax,0000003fh ;offset     ;/
 and  ebx,not 1  ;addr AND not 1;-align curr addr (for below offset)
 lea  ebx,[ebx+eax*2+2]         ;-and add offset to node0 (node1 if at addr+1)
 add  edx,edx    ;=cy           ;\
 jz   @@collect_bits            ; get next bit to carry
</PRE></TD></TR></TBODY></TABLE>@@collect_back: ;/<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> jnc  short @@node0             ;\
 inc  ebx         ;addr+1       ; node0 or node1
 add  ch,ch       ;bit6 to bit7 ;
</PRE></TD></TR></TBODY></TABLE>@@node0: ;/<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> add  ch,ch       ;bit7 to cy   ;\check if next node is data
 jnc  short @@lop ;next child   ;/
 ;--- data node ---
 mov  al,byte ptr ds:[ebx]      ;\
</PRE></TD></TR></TBODY></TABLE>;XXX AND AL,MASK(bitwidth) ;<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> or   byte ptr [@@data],al      ;
 ror  dword ptr [@@data],cl     ;/
 mov  ebx,@@root                ;-back to root node
 add  byte ptr [@@cnt],cl       ;\check if collected 32bit data
 js   short @@lop               ;/which would be to be stored in RAM now
 mov  eax,dword ptr [@@data]    ;\
 stosd                          ; store data, check if done
 sub  @@len,4                   ;
 ja   short @@data_lop          ;/
</PRE></TD></TR></TBODY></TABLE>@@done:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> ret
</PRE></TD></TR></TBODY></TABLE>;---<BR>@@collect_bits: ;in: cy=1 (stop-bit)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> lodsd          ;cy=same (!)
 adc  eax,eax   ;bit31 to cy, and bit0=1 (=incoming cy=stop-bit)
 mov  edx,eax
 jmp  short @@collect_back  ;out: cy
</PRE></TD></TR></TBODY></TABLE>;---<BR><BR><BR><BR><BR><B>SWI 11h 
(GBA/NDS7/NDS9) - LZ77UnCompWram</B><BR><B>SWI 12h (GBA/NDS7/NDS9) - 
LZ77UnCompVram (NDS: with Callback)</B><BR>Expands LZ77-compressed data. The 
Wram function is faster, and writes in units of 8bits. For the Vram function the 
destination must be halfword aligned, data is written in units of 16bits.<BR>If 
the size of the compressed data is not a multiple of 4, please adjust it as much 
as possible by padding with 0. Align the source address to a 4-Byte 
boundary.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   Source address, pointing to data as such:
        Data header (32bit)
          Bit 0-3   Reserved
          Bit 4-7   Compressed type (must be 1 for LZ77)
          Bit 8-31  Size of decompressed data
        Repeat below. Each Flag Byte followed by eight Blocks.
        Flag data (8bit)
          Bit 0-7   Type Flags for next 8 Blocks, MSB first
        Block Type 0 - Uncompressed - Copy 1 Byte from Source to Dest
          Bit 0-7   One data byte to be copied to dest
        Block Type 1 - Compressed - Copy N+3 Bytes from Dest-Disp-1 to Dest
          Bit 0-3   Disp MSBs
          Bit 4-7   Number of bytes to copy (minus 3)
          Bit 8-15  Disp LSBs
  r1   Destination address
  r2  Callback parameter (NDS SWI 12h only, see Callback notes below)
  r3  Callback structure (NDS SWI 12h only, see Callback notes below)
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR><BR><B>SWI 14h 
(GBA/NDS7/NDS9) - RLUnCompWram</B><BR><B>SWI 15h (GBA/NDS7/NDS9) - RLUnCompVram 
(NDS: with Callback)</B><BR>Expands run-length compressed data. The Wram 
function is faster, and writes in units of 8bits. For the Vram function the 
destination must be halfword aligned, data is written in units of 16bits.<BR>If 
the size of the compressed data is not a multiple of 4, please adjust it as much 
as possible by padding with 0. Align the source address to a 4Byte boundary.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Source Address, pointing to data as such:
       Data header (32bit)
         Bit 0-3   Reserved
         Bit 4-7   Compressed type (must be 3 for run-length)
         Bit 8-31  Size of decompressed data
       Repeat below. Each Flag Byte followed by one or more Data Bytes.
       Flag data (8bit)
         Bit 0-6   Expanded Data Length (uncompressed N-1, compressed N-3)
         Bit 7     Flag (0=uncompressed, 1=compressed)
       Data Byte(s) - N uncompressed bytes, or 1 byte repeated N times
  r1  Destination Address
  r2  Callback parameter (NDS SWI 15h only, see Callback notes below)
  r3  Callback structure (NDS SWI 15h only, see Callback notes below)
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR><B>NDS Decompression Callbacks</B><BR>On NDS7/NDS9, 
the SWI 12h, 13h, 15h functions are reading source data from callback functions 
(rather than directly from memory). The callback functions may read normal data 
from memory, or from other devices, such like directly from the gamepak bus, 
without storing the source data in memory. The downside is that the callback 
mechanism makes the function very slow, furthermore, NDS7/NDS9 SWI 12h, 13h, 15h 
are using THUMB code, and variables on stack, alltogether that makes the whole 
shit very-very-very slow.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r2 = user defined callback parameter (passed on to Open function)
  r3 = pointer to callback structure
</PRE></TD></TR></TBODY></TABLE>Callback structure (five 32bit pointers to 
callback functions)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Open_and_get_32bit (eg. LDR r0,[r0], get header)
  Close              (optional, 0=none)
  Get_8bit           (eg. LDRB r0,[r0])
  Get_16bit          (not used)
  Get_32bit          (used by Huffman only)
</PRE></TD></TR></TBODY></TABLE>All functions may use ARM or THUMB code 
(indicated by address bit0). The current source address (r0) is passed to all 
callback functions. Additionally, the initial destination address (r1), and a 
user defined parameter (r2) are passed to the Open function. All functions have 
return values in r0. The Open function normally returns the first word 
(containing positive length and type), alternatively it may return a negative 
error code to abort/reject decompression. The Close function, if it is defined, 
should return zero (or any positive value), or a negative errorcode. The other 
functions return raw data, without errorcodes. The SWI returns the length of 
decompressed data, or the signed errorcode from the Open/Close 
functions.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosmemorycopy></A><FONT size=+2>&nbsp;BIOS Memory 
    Copy</FONT></TD></TR></TBODY></TABLE><BR>CpuFastSet<BR>CpuSet<BR><BR><B>SWI 0Ch 
(GBA/NDS7/NDS9) - CpuFastSet</B><BR>Memory copy/fill in units of 32 bytes. 
Memcopy is implemented as repeated LDMIA/STMIA [Rb]!,r2-r9 instructions. Memfill 
as single LDR followed by repeated STMIA [Rb]!,r2-r9. After processing all 
32-byte-blocks, the NDS additonally processes the remaining words as 4-byte 
blocks. BUG: The NDS uses the fast 32-byte-block processing only for the first N 
bytes (not for the first N words), so only the first quarter of the memory block 
is FAST, the remaining three quarters are SLOWLY copied word-by-word.<BR>The 
length is specifed as wordcount, ie. the number of bytes divided by 4.<BR>On the 
GBA, the length must be a multiple of 8 words (32 bytes). On NDS, the length may 
be any number of words (4 bytes).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0    Source address        (must be aligned by 4)
  r1    Destination address   (must be aligned by 4)
  r2    Length/Mode
          Bit 0-20  Wordcount (GBA: must be a multiple of 8 words)
          Bit 24    Fixed Source Address (0=Copy, 1=Fill by WORD[r0])
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR><B>SWI 0Bh (GBA/NDS7/NDS9) - CpuSet</B><BR>Memory 
copy/fill in units of 4 bytes or 2 bytes. Memcopy is implemented as repeated 
LDMIA/STMIA [Rb]!,r3 or LDRH/STRH r3,[r0,r5] instructions. Memfill as single 
LDMIA or LDRH followed by repeated STMIA [Rb]!,r3 or STRH r3,[r0,r5].<BR>The 
length must be a multiple of 4 bytes (32bit mode) or 2 bytes (16bit mode). The 
(half)wordcount in r2 must be length/4 (32bit mode) or length/2 (16bit mode), 
ie. length in word/halfword units rather than byte units.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0    Source address        (must be aligned by 4 for 32bit, by 2 for 16bit)
  r1    Destination address   (must be aligned by 4 for 32bit, by 2 for 16bit)
  r2    Length/Mode
          Bit 0-20  Wordcount (for 32bit), or Halfwordcount (for 16bit)
          Bit 24    Fixed Source Address (0=Copy, 1=Fill by {HALF}WORD[r0])
          Bit 26    Datasize (0=16bit, 1=32bit)
</PRE></TD></TR></TBODY></TABLE>Return: No return value, Data written to 
destination address.<BR><BR>Note: On GBA and NDS7, these two functions will 
silently reject to do anything if the source start or end addresses are reaching 
into the BIOS area. The NDS9 doesn't have such read-proctection.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=bioshaltfunctions></A><FONT size=+2>&nbsp;BIOS Halt 
      Functions</FONT></TD></TR></TBODY></TABLE><BR>Halt<BR>IntrWait<BR>VBlankIntrWait<BR>Stop/Sleep<BR>CustomHalt<BR><BR><B>SWI 
02h (GBA) or SWI 06h (NDS7/NDS9) - Halt</B><BR>Halts the CPU until an interrupt 
request occurs. The CPU is switched into low-power mode, all other circuits 
(video, sound, timers, serial, keypad, system clock) are kept operating.<BR>Halt 
mode is terminated when any enabled interrupts are requested, that is when (IE 
AND IF) is not zero, the GBA locks up if that condition doesn't get true. 
However, the state of CPUs IRQ disable bit in CPSR register, and the IME 
register are don't care, Halt passes through even if either one has disabled 
interrupts.<BR>On GBA and NDS7, Halt is implemented by writing to HALTCNT, Port 
4000301h. On NDS9, Halt is implemted by writing to System Control Coprocessor 
(mov p15,0,c7,c0,4,r0 opcode), this opcode hangs if IME=0.<BR>No parameters, no 
return value.<BR>(GBA/NDS7: all registers unchanged, NDS9: R0 
destroyed)<BR><BR><B>SWI 04h (GBA/NDS7/NDS9) - IntrWait</B><BR>Continues to wait 
in Halt state until one (or more) of the specified interrupt(s) do occur. The 
function forcefully sets IME=1. When using multiple interrupts at the same time, 
this function is having less overhead than repeatedly calling the Halt 
function.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0    0=Return immediately if an old flag was already set (NDS9: bugged!)
        1=Discard old flags, wait until a NEW flag becomes set
  r1    Interrupt flag(s) to wait for (same format as IE/IF registers)
</PRE></TD></TR></TBODY></TABLE>Caution: When using IntrWait or VBlankIntrWait, 
the user interrupt handler MUST update the BIOS Interrupt Flags value in RAM; 
when acknowleding processed interrupt(s) by writing a value to the IF register, 
the same value should be also ORed to the BIOS Interrupt Flags value, at 
following memory location:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Host     GBA (16bit)  NDS7 (32bit)  NDS9 (32bit)
  Address  [3007FF8h]   [380FFF8h]    [DTCM+3FF8h]
</PRE></TD></TR></TBODY></TABLE>NDS9: BUG: No Discard (r0=0) doesn't work. The 
function always waits for at least one IRQ to occur (no matter which, including 
IRQs that are not selected in r1), even if the desired flag was already set. NB. 
the same bug is also found in the GBA/NDS7 functions, but it's compensated by a 
second bug, ie. the GBA/NDS7 functions are working okay because their "bug 
doesn't work".<BR>Return: No return value, the selected flag(s) are 
automatically reset in BIOS Interrupt Flags value in RAM upon 
return.<BR><BR><B>SWI 05h (GBA/NDS7/NDS9) - VBlankIntrWait</B><BR>Continues to 
wait in Halt status until a new V-Blank interrupt occurs.<BR>The function sets 
r0=1 and r1=1 and then executes IntrWait (SWI 04h), see IntrWait for 
details.<BR>No parameters, no return value.<BR><BR><B>SWI 03h (GBA) - 
Stop</B><BR>Switches the GBA into very low power mode (to be used similar as a 
screen-saver). The CPU, System Clock, Sound, Video, SIO-Shift Clock, DMAs, and 
Timers are stopped.<BR>Stop state can be terminated by the following interrupts 
only (as far as enabled in IE register): Joypad, Game Pak, or 
General-Purpose-SIO.<BR>"The system clock is stopped so the IF flag is not 
set."<BR>Preparation for Stop:<BR>Disable Video before implementing Stop 
(otherwise Video just freezes, but still keeps consuming battery power). 
Possibly required to disable Sound also? Obviously, it'd be also recommended to 
disable any external hardware (such like Rumble or Infra-Red) as far as 
possible.<BR>No parameters, no return value.<BR><BR><B>SWI 07h (NDS7) - 
Sleep</B><BR>No info, probably similar as GBA SWI 03h (Stop). Sleep is 
implemented for NDS7 only, not for NDS9, not sure if the functions stops BOTH 
NDS7 and NDS9?<BR><BR><B>SWI 27h (GBA) or SWI 1Fh (NDS7) - CustomHalt 
(Undocumented)</B><BR>Writes the 8bit parameter value to HALTCNT, below values 
are equivalent to Halt and Stop/Sleep functions, other values reserved, purpose 
unknown.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r2  8bit parameter (GBA: 00h=Halt, 80h=Stop) (NDS7: 80h=Halt, C0h=Sleep)
</PRE></TD></TR></TBODY></TABLE>No return value.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosresetfunctions></A><FONT size=+2>&nbsp;BIOS Reset 
      Functions</FONT></TD></TR></TBODY></TABLE><BR>SoftReset<BR>RegisterRamReset<BR>HardReset<BR><BR><B>SWI 
00h - SoftReset</B><BR>Clears 200h bytes of RAM (containing stacks, and BIOS IRQ 
vector/flags), initializes system, supervisor, and irq stack pointers, sets 
R0-R12, LR_svc, SPSR_svc, LR_irq, and SPSR_irq to zero, and enters system 
mode.<BR>Note that the NDS9 stack registers are hardcoded (the DTCM base should 
be set to the default setting of 0800000h). The NDS9 function additionally 
flushes caches and write buffer, and sets the CP15 control register to 
12078h.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Host  sp_svc    sp_irq    sp_sys    zerofilled area       return address
  GBA   3007FE0h  3007FA0h  3007F00h  [3007E00h..3007FFFh]  Flag[3007FFAh]
  NDS7  380FFDCh  380FFB0h  380FF00h  [380FE00h..380FFFFh]  Addr[27FFE34h]
  NDS9  0803FC0h  0803FA0h  0803EC0h  [DTCM+3E00h..3FFFh]   Addr[27FFE24h]
</PRE></TD></TR></TBODY></TABLE>The NDS7/NDS9 return addresses at 
[27FFE34h/27FFE24h] are usually containing copies of Cartridge Header 
[034h/024h] entry points, which may select ARM/THUMB state via bit0. The GBA 
return address 8bit flag is interpreted as 00h=8000000h (ROM), or 
01h-FFh=2000000h (RAM), entered in ARM state.<BR>Note: The reset is applied only 
to the CPU that has executed the SWI (ie. on the NDS, the other CPU will remain 
unaffected).<BR>Return: Does not return to calling procedure, instead, loads the 
above return address into R14, and then jumps to that address by a "BX R14" 
opcode.<BR><BR><B>SWI 01h (GBA) - RegisterRamReset</B><BR>Resets the I/O 
registers and RAM specified in ResetFlags. However, it does not clear the CPU 
internal RAM area from 3007E00h-3007FFFh.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  ResetFlags
       Bit   Expl.
       0     Clear 256K on-board WRAM  ;-don't use when returning to WRAM
       1     Clear 32K in-chip WRAM    ;-excluding last 200h bytes
       2     Clear Palette
       3     Clear VRAM
       4     Clear OAM              ;-zerofilled! does NOT disable OBJs!
       5     Reset SIO registers    ;-switches to general purpose mode!
       6     Reset Sound registers
       7     Reset all other registers (except SIO, Sound)
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR>Bug: LSBs of 
SIODATA32 are always destroyed, even if Bit5 of R0 was cleared.<BR>The function 
always switches the screen into forced blank by setting DISPCNT=0080h 
(regardless of incoming R0, screen becomes white).<BR><BR><B>SWI 26h (GBA) - 
HardReset (Undocumented)</B><BR>This function reboots the GBA (including for 
getting through the time-consuming nintendo intro, which is making the function 
particularly useless and annoying).<BR>Parameters: None. Return: 
Never/Reboot.<BR>Execution Time: About 2 seconds (!)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosmiscfunctions></A><FONT size=+2>&nbsp;BIOS Misc 
      Functions</FONT></TD></TR></TBODY></TABLE><BR>GetBiosChecksum<BR>WaitByLoop<BR>GetCRC16<BR>IsDebugger<BR>GetSineTable<BR>GetPitchTable<BR>GetVolumeTable<BR>CustomPost<BR>GetBootProcs<BR><BR><B>SWI 
0Dh (GBA) - GetBiosChecksum (Undocumented)</B><BR>Calculates the checksum of the 
BIOS ROM (by reading in 32bit units, and adding up these values). IRQ and FIQ 
are disabled during execution.<BR>The checksum is BAAE187Fh (GBA and GBA SP), or 
BAAE1880h (DS in GBA mode, whereas the only difference is that the byte at 
[3F0Ch] is changed from 00h to 01h, otherwise the BIOS is 1:1 same as GBA BIOS, 
it does even include multiboot code).<BR>Parameters: None. Return: 
r0=Checksum.<BR><BR><B>SWI 03h (NDS7/NDS9) - WaitByLoop</B><BR>Performs a "LOP: 
SUB R0,1 / BGT LOP" wait loop, the loop is executed in BIOS memory, which 
provides reliable timings (regardless of the memory waitstates &amp; cache state 
of the calling procedure). Intended only for short delays (eg. flash memory 
programming cycles).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Delay value (should be in range 1..7FFFFFFFh)
</PRE></TD></TR></TBODY></TABLE>Execution Time: NDS7: R0*4 cycles, plus some 
overload on SWI handling.<BR>Execution Time: NDS9: R0*2 (cache on), or R0*8 
(cache off), plus overload.<BR>Note: Both NDS7 and NDS9 timings are counted in 
33.51MHz units.<BR>Return: No return value.<BR><BR><B>SWI 0Eh (NDS7/NDS9) - 
GetCRC16</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Initial CRC value (16bit, usually FFFFh)
  r1  Start Address   (must be aligned by 2)
  r2  Length in bytes (must be aligned by 2)
</PRE></TD></TR></TBODY></TABLE>CRC16 checksums can be calculated as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  val[0..7] = C0C1h,C181h,C301h,C601h,CC01h,D801h,F001h,A001h
  for i=start to end
    crc=crc xor byte[i]
    for j=0 to 7
      crc=crc shr 1:if carry then crc=crc xor (val[j] shl (7-j))
    next j
  next i
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Calculated 16bit CRC Value
</PRE></TD></TR></TBODY></TABLE>Additionally, if the length is nonzero, r3 
contains the last processed halfword at [addr+len-2]. Unlike most other NDS7 SWI 
functions which reject to read from BIOS memory, this allows to dump the NDS7 
BIOS (except for the memory region that is locked via BIOSPROT Port 
4000308h).<BR><BR><B>SWI 0Fh (NDS7/NDS9) - IsDebugger</B><BR>Detects if 4MB 
(normal) or 8MB (debug version) Main RAM installed.<BR>Return: r0 = result 
(0=normal console 4MB, 1=debug version 8MB)<BR>Destroys halfword at [27FFFFAh] 
(NDS7) or [27FFFF8h] (NDS9)!<BR>The SWI 0Fh function doesn't work stable if it 
gets interrupted by an interrupt which is calling SWI 0Fh, which would destroy 
the above halfword scratch value (unless the IRQ handler has saved/restored the 
halfword).<BR><BR><B>SWI 1Ah (NDS7) - GetSineTable</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Index (0..3Fh) (must be in that range, otherwise returns garbage)
</PRE></TD></TR></TBODY></TABLE>Return: r0 = Desired Entry (0000h..7FF5h) ;SIN(0 
.. 88.6 degrees)*8000h<BR><BR><B>SWI 1Bh (NDS7) - GetPitchTable</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Index (0..2FFh) (must be in that range, otherwise returns garbage)
</PRE></TD></TR></TBODY></TABLE>Return: r0 = Desired Entry (0000h..FF8Ah) 
(unsigned)<BR><BR><B>SWI 1Ch (NDS7) - GetVolumeTable</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Index (0..2D3h) (must be in that range, otherwise returns garbage)
</PRE></TD></TR></TBODY></TABLE>Return: r0 = Desired Entry (00h..7Fh) 
(unsigned)<BR><BR><B>SWI 1Fh (NDS9) - CustomPost</B><BR>Writes to the POSTFLG 
register, probably for use by Firmware boot procedure.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  32bit value, to be written to POSTFLG, Port 4000300h
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR><BR><B>SWI 1Dh 
(NDS7) - GetBootProcs</B><BR>Returns addresses of Gamecart boot 
procedure/interrupt handler, probably for use by Firmware boot procedure. The 
return values are somewhat XORed by each other. Most of the returned functions 
won't work if the POSTFLG register is set.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biosmultibootsinglegamepak></A><FONT size=+2>&nbsp;BIOS Multi 
      Boot (Single Game 
Pak)</FONT></TD></TR></TBODY></TABLE><BR>MultiBoot<BR><BR><B>SWI 25h (GBA) - 
MultiBoot</B><BR>This function uploads &amp; starts program code to slave GBAs, 
allowing to launch programs on slave units even if no cartridge is inserted into 
the slaves (this works because all GBA BIOSes contain built-in download 
procedures in ROM).<BR>However, the SWI 25h BIOS upload function covers only 45% 
of the required Transmission Protocol, the other 55% must be coded in the master 
cartridge (see Transmission Protocol below).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Pointer to MultiBootParam structure
  r1  Transfer Mode (undocumented)
       0=256KHz, 32bit, Normal mode    (fast and stable)
       1=115KHz, 16bit, MultiPlay mode (default, slow, up to three slaves)
       2=2MHz,   32bit, Normal mode    (fastest but maybe unstable)
  Note: HLL-programmers that are using the MultiBoot(param_ptr) macro cannot
  specify the transfer mode and will be forcefully using MultiPlay mode.
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  0=okay, 1=failed
</PRE></TD></TR></TBODY></TABLE>See below for more details.<BR><BR><B>Multiboot 
Parameter Structure</B><BR>Size of parameter structure should be 4Ch bytes (the 
current GBA BIOS uses only first 44h bytes though). The following entries must 
be set before calling SWI 25h:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Name/Expl.
  14h  1    handshake_data (entry used for normal mode only)
  19h  3    client_data[1,2,3]
  1Ch  1    palette_data
  1Eh  1    client_bit (Bit 1-3 set if child 1-3 detected)
  20h  4    boot_srcp  (typically 8000000h+0C0h)
  24h  4    boot_endp  (typically 8000000h+0C0h+length)
</PRE></TD></TR></TBODY></TABLE>The transfer length (excluding header data) 
should be a multiple of 10h, minimum length 100h, max 3FF40h (ca. 256KBytes). 
Set palette_data as "81h+color*10h+direction*8+speed*2", or as "0f1h+color*2" 
for fixed palette, whereas color=0..6, speed=0..3, direction=0..1. The other 
entries (handshake_data, client_data[1-3], and client_bit) must be same as 
specified in Transmission Protocol (see below hh,cc,y).<BR><BR><B>Multiboot 
Transfer Protocol</B><BR>Below describes the complete transfer protocol, 
normally only the Initiation part must be programmed in the master cartridge, 
the main data transfer can be then performed by calling SWI 25h, the slave 
program is started after SWI 25h completion.<BR>The ending handshake is normally 
not required, when using it, note that you will need custom code in BOTH master 
and slave programs.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Times  Send   Receive  Expl.
  -----------------------Required Transfer Initiation in master program
  ...    6200   FFFF     Slave not in multiplay/normal mode yet
  1      6200   0000     Slave entered correct mode now
  15     6200   720x     Repeat 15 times, if failed: delay 1/16s and restart
  1      610y   720x     Recognition okay, exchange master/slave info
  60h    xxxx   NN0x     Transfer C0h bytes header data in units of 16bits
  1      6200   000x     Transfer of header data completed
  1      620y   720x     Exchange master/slave info again
  ...    63pp   720x     Wait until all slaves reply 73cc instead 720x
  1      63pp   73cc     Send palette_data and receive client_data[1-3]
  1      64hh   73uu     Send handshake_data for final transfer completion
  -----------------------Below is SWI 25h MultiBoot handler in BIOS
  DELAY  -      -        Wait 1/16 seconds at master side
  1      llll   73rr     Send length information and receive random data[1-3]
  LEN    yyyy   nnnn     Transfer main data block in units of 16 or 32 bits
  1      0065   nnnn     Transfer of main data block completed, request CRC
  ...    0065   0074     Wait until all slaves reply 0075 instead 0074
  1      0065   0075     All slaves ready for CRC transfer
  1      0066   0075     Signalize that transfer of CRC follows
  1      zzzz   zzzz     Exchange CRC must be same for master and slaves
  -----------------------Optional Handshake (NOT part of master/slave BIOS)
  ...    ....   ....     Exchange whatever custom data
</PRE></TD></TR></TBODY></TABLE>Legend for above Protocol<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  y     client_bit, bit(s) 1-3 set if slave(s) 1-3 detected
  x     bit 1,2,or 3 set if slave 1,2,or 3
  xxxx  header data, transferred in 16bit (!) units (even in 32bit normal mode)
  nn    response value for header transfer, decreasing 60h..01h
  pp    palette_data
  cc    random client_data[1..3] from slave 1-3, FFh if slave not exists
  hh    handshake_data, 11h+client_data[1]+client_data[2]+client_data[3]
  uu    random data, not used, ignore this value
</PRE></TD></TR></TBODY></TABLE>Below automatically calculated by SWI 25h BIOS 
function (don't care about)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  llll  download length/4-34h
  rr    random data from each slave for encryption, FFh if slave not exists
  yyyy  encoded data in 16bit (multiplay) or 32bit (normal mode) units
  nnnn  response value, lower 16bit of destadr in GBA memory (00C0h and up)
  zzzz  16bit download CRC value, must be same for master and slaves
</PRE></TD></TR></TBODY></TABLE>Pseudo Code for SWI 25h Transfer with Checksum 
and Encryption calculations<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  if normal_mode    then c=C387h:x=C37Bh:k=43202F2Fh
  if multiplay_mode then c=FFF8h:x=A517h:k=6465646Fh
  m=dword(pp,cc,cc,cc):f=dword(hh,rr,rr,rr)
  for ptr=000000C0h to (file_size-4) step 4
    c=c xor data[ptr]:for i=1 to 32:c=c shr 1:if carry then c=c xor x:next
    m=(6F646573h*m)+1
    send_32_or_2x16 (data[ptr] xor (-2000000h-ptr) xor m xor k)
  next
  c=c xor f:for i=1 to 32:c=c shr 1:if carry then c=c xor x:next
  wait_all_units_ready_for_checksum:send_32_or_1x16 (c)
</PRE></TD></TR></TBODY></TABLE>Whereas, explained: 
c=chksum,x=chkxor,f=chkfin,k=keyxor,m=keymul<BR><BR><B>Multiboot 
Communication</B><BR>In Multiplay mode, master sends 16bit data, and receives 
16bit data from each slave (or FFFFh if none). In Normal mode, master sends 
32bit data (upper 16bit zero, lower 16bit as for multipay mode), and receives 
32bit data (upper 16bit as for multiplay mode, and lower 16bit same as lower 
16bit previously sent by master). Because SIODATA32 occupies same addresses as 
SIOMULTI0-1, the same transfer code can be used for both multiplay and normal 
mode (in normal mode SIOMULTI2-3 should be forced to FFFFh though). After each 
transfer, master should wait for Start bit cleared in SIOCNT register, followed 
by a 36us delay.<BR>Note: The multiboot slave would also recognize data being 
sent in Joybus mode, however, master GBAs cannot use joybus mode (because GBA 
hardware cannot act as master in joybus mode).<BR><BR><B>Multiboot Slave 
Header</B><BR>The transferred Header block is written to 2000000-20000BFh in 
slave RAM, the header must contain valid data (identically as for normal 
ROM-cartridge headers, including a copy of the Nintendo logo, correct header 
CRC, etc.), in most cases it'd be recommended just to transfer a copy of the 
master cartridges header from 8000000h-80000BFh.<BR><BR><B>Multiboot Slave 
Program/Data</B><BR>The transferred main program/data block is written to 
20000C0h and up (max 203FFFFh) in slave RAM, note that absolute addresses in the 
program must be then originated at 2000000h rather than 8000000h. In case that 
the master cartridge is 256K or less, it could just transfer a copy of the whole 
cartridge at 80000C0h and up, the master should then copy &amp; execute its own 
ROM data into RAM as well.<BR><BR><B>Multiboot Slave Extended Header</B><BR>For 
Multiboot slaves, separate Entry Point(s) must be defined at the beginning of 
the Program/Data block (the Entry Point in the normal header is ignored), also 
some reserved bytes in this section are overwritten by the Multiboot procedure. 
For more information see chapter about Cartridge Header.<BR><BR><B>Multiboot 
Slave with Cartridge</B><BR>Beside for slaves without cartridge, multiboot can 
be also used for slaves which do have a cartridge inserted, if so, SELECT and 
START must be kept held down during power-on in order to switch the slave GBA 
into Multiboot mode (ie. to prevent it from starting the cartridge as 
normally).<BR>The general idea is to enable newer programs to link to any 
existing older GBA programs, even if these older programs originally didn't have 
been intended to support linking.<BR>The uploaded program may access the slaves 
SRAM, Flash ROM, or EEPROM (if any, allowing to read out or modify slave game 
positions), as well as cartridge ROM at 80000A0h-8000FFFh (the first 4KBytes, 
excluding the nintendo logo, allowing to read out the cartridge name from the 
header, for example).<BR>The main part of the cartridge ROM is meant to be 
locked out in order to prevent software pirates from uploading "intruder" 
programs which would send back a copy of the whole cartridge to the master, 
however, for good or evil, at present time, current GBA models and GBA carts do 
not seem to contain any such protection.<BR><BR><B>Uploading Programs from 
PC</B><BR>Beside for the ability to upload a program from one GBA to another, 
this feature can be also used to upload small programs from a PC to a GBA. For 
more information see chapter about External Connectors.<BR><BR><B>Nintendo 
DS</B><BR>The GBA multiboot function requires a link port, and so, works on GBA 
and GBA SP only. The Nintendo DS in GBA mode does include the multiboot BIOS 
function, but it won't be of any use as the DS doesn't have a link 
port.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=biossoundfunctions></A><FONT size=+2>&nbsp;BIOS Sound 
      Functions</FONT></TD></TR></TBODY></TABLE><BR>MidiKey2Freq<BR>SoundBias<BR>SoundChannelClear<BR>SoundDriverInit<BR>SoundDriverMain<BR>SoundDriverMode<BR>SoundDriverVSync<BR>SoundDriverVSyncOff<BR>SoundDriverVSyncOn<BR>SoundWhatever0..4<BR>SoundGetJumpList<BR><BR><B>SWI 
1Fh (GBA) - MidiKey2Freq</B><BR>Calculates the value of the assignment to 
((SoundArea)sa).vchn[x].fr when playing the wave data, wa, with the interval 
(MIDI KEY) mk and the fine adjustment value (halftones=256) fp.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  WaveData* wa
  r1  u8 mk
  r2  u8 fp
</PRE></TD></TR></TBODY></TABLE>Return:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  u32
</PRE></TD></TR></TBODY></TABLE>This function is particularly popular because it 
allows to read from BIOS memory without copy protection range checks. The 
formula to read one byte (a) from address (i, 0..3FFF) is:<BR>a = 
(MidiKey2Freq(i-(((i AND 3)+1)OR 3), 168, 0) * 2) SHR 24<BR><BR><B>SWI 19h (GBA) 
or SWI 08h (NDS7) - SoundBias</B><BR>Increments or decrements the current level 
of the SOUNDBIAS register (with short delays) until reaching the desired new 
level. The upper bits of the register are kept unchanged.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0   BIAS level (0=Level 000h, any other value=Level 200h)
  r1   Delay Count (NDS only) (GBA uses a fixed delay count of 8)
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR><BR><B>SWI 1Eh (GBA) 
- SoundChannelClear</B><BR>Clears all direct sound channels and stops the 
sound.<BR>This function may not operate properly when the library which expands 
the sound driver feature is combined afterwards. In this case, do not use 
it.<BR>No parameters, no return value.<BR><BR><B>SWI 1Ah (GBA) - 
SoundDriverInit</B><BR>Initializes the sound driver. Call this only once when 
the game starts up.<BR>It is essential that the work area already be secured at 
the time this function is called.<BR>You cannot execute this driver multiple 
times, even if separate work areas have been prepared.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Pointer to work area for sound driver, SoundArea structure as follows:
       SoundArea (sa) Structure
        u32    ident      Flag the system checks to see whether the
                          work area has been initialized and whether it
                          is currently being accessed.
        vu8    DmaCount   User access prohibited
        u8     reverb     Variable for applying reverb effects to direct sound
        u16    d1         User access prohibited
        void   (*func)()  User access prohibited
        int    intp       User access prohibited
        void*  NoUse      User access prohibited
        SndCh  vchn[MAX]  The structure array for controlling the direct
                          sound channels (currently 8 channels are
                          available). The term "channel" here does
                          not refer to hardware channels, but rather to
                          virtual constructs inside the sound driver.
        s8     pcmbuf[PCM_BF*2]
       SoundChannel Structure
        u8         sf     The flag indicating the status of this channel.
                          When 0 sound is stopped.
                          To start sound, set other parameters and
                          then write 80h to here.
                          To stop sound, logical OR 40h for a
                          release-attached off (key-off), or write zero
                          for a pause. The use of other bits is
                          prohibited.
        u8         r1     User access prohibited
        u8         rv     Sound volume output to right side
        u8         lv     Sound volume output to left side
        u8         at     The attack value of the envelope. When the
                          sound starts, the volume begins at zero and
                          increases every 1/60 second. When it
                          reaches 255, the process moves on to the
                          next decay value.
        u8         de     The decay value of the envelope. It is
                          multiplied by "this value/256" every 1/60
                          sec. and when sustain value is reached, the
                          process moves to the sustain condition.
        u8         su     The sustain value of the envelope. The
                          sound is sustained by this amount.
                          (Actually, multiplied by rv/256, lv/256 and
                          output left and right.)
        u8         re     The release value of the envelope. Key-off
                          (logical OR 40h in sf) to enter this state.
                          The value is multiplied by "this value/256"
                          every 1/60 sec. and when it reaches zero,
                          this channel is completely stopped.
        u8         r2[4]  User access prohibited
        u32        fr     The frequency of the produced sound.
                          Write the value obtained with the
                          MidiKey2Freq function here.
        WaveData*  wp     Pointer to the sound's waveform data. The waveform
                          data can be generated automatically from the AIFF
                          file using the tool (aif2agb.exe), so users normally
                          do not need to create this themselves.
        u32        r3[6]  User access prohibited
        u8         r4[4]  User access prohibited
       WaveData Structure
        u16   type    Indicates the data type. This is currently not used.
        u16   stat    At the present time, non-looped (1 shot) waveform
                      is 0000h and forward loop is 4000h.
        u32   freq    This value is used to calculate the frequency.
                      It is obtained using the following formula:
                      sampling rate x 2^((180-original MIDI key)/12)
        u32   loop    Loop pointer (start of loop)
        u32   size    Number of samples (end position)
        s8    data[]  The actual waveform data. Takes (number of samples+1)
                      bytes of 8bit signed linear uncompressed data. The last
                      byte is zero for a non-looped waveform, and the same
                      value as the loop pointer data for a looped waveform.
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR><BR><B>SWI 1Ch (GBA) 
- SoundDriverMain</B><BR>Main of the sound driver.<BR>Call every 1/60 of a 
second. The flow of the process is to call SoundDriverVSync, which is explained 
later, immediately after the V-Blank interrupt.<BR>After that, this routine is 
called after BG and OBJ processing is executed.<BR>No parameters, no return 
value.<BR><BR><B>SWI 1Bh (GBA) - SoundDriverMode</B><BR>Sets the sound driver 
operation mode.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Sound driver operation mode
       Bit    Expl.
       0-6    Direct Sound Reverb value (0-127, default=0) (ignored if Bit7=0)
       7      Direct Sound Reverb set (0=ignore, 1=apply reverb value)
       8-11   Direct Sound Simultaneously-produced (1-12 channels, default 8)
       12-15  Direct Sound Master volume (1-15, default 15)
       16-19  Direct Sound Playback Frequency (1-12 = 5734,7884,10512,13379,
              15768,18157,21024,26758,31536,36314,40137,42048, def 4=13379 Hz)
       20-23  Final number of D/A converter bits (8-11 = 9-6bits, def. 9=8bits)
       24-31  Not used.
</PRE></TD></TR></TBODY></TABLE>Return: No return value.<BR><BR><B>SWI 1Dh (GBA) 
- SoundDriverVSync</B><BR>An extremely short system call that resets the sound 
DMA. The timing is extremely critical, so call this function immediately after 
the V-Blank interrupt every 1/60 second.<BR>No parameters, no return 
value.<BR><BR><B>SWI 28h (GBA) - SoundDriverVSyncOff</B><BR>Due to problems with 
the main program if the V-Blank interrupts are stopped, and SoundDriverVSync 
cannot be called every 1/60 a second, this function must be used to stop sound 
DMA.<BR>Otherwise, even if you exceed the limit of the buffer the DMA will not 
stop and noise will result.<BR>No parameters, no return value.<BR><BR><B>SWI 29h 
(GBA) - SoundDriverVSyncOn</B><BR>This function restarts the sound DMA stopped 
with the previously described SoundDriverVSyncOff.<BR>After calling this 
function, have a V-Blank occur within 2/60 of a second and call 
SoundDriverVSync.<BR>No parameters, no return value.<BR><BR><B>SWI 20h..24h 
(GBA) - SoundWhatever0..4 (Undocumented)</B><BR>Whatever undocumented 
sound-related BIOS functions.<BR><BR><B>SWI 2Ah (GBA) - SoundGetJumpList 
(Undocumented)</B><BR>Receives pointers to 36 additional sound-related BIOS 
functions.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  r0  Destination address (must be aligned by 4) (120h bytes buffer)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=unpredictablethings></A><FONT size=+2>&nbsp;Unpredictable 
      Things</FONT></TD></TR></TBODY></TABLE><BR><B>Forward</B><BR>Most of the below 
is caused by 'traces' from previous operations which have used the databus. No 
promises that the results are stable on all current or future GBA models, and/or 
under all temperature and interference circumstances.<BR>Also, below specifies 
32bit data accesses only. When reading units less than 32bit, data is rotated 
depending on the alignment of the originally specified address, and 8bit or 
16bit are then isolated from the 32bit value as usually.<BR><BR><B>Reading from 
BIOS Memory (00000000-00003FFF)</B><BR>The BIOS memory is protected against 
reading, the GBA allows to read opcodes or data only if the program counter is 
located inside of the BIOS area. If the program counter is not in the BIOS area, 
reading will return the most recent successfully fetched BIOS opcode (eg. the 
opcode at [00DCh+8] after startup and SoftReset, the opcode at [0134h+8] during 
IRQ execution, and opcode at [013Ch+8] after IRQ execution, and opcode at 
[0188h+8] after SWI execution).<BR><BR><B>Reading from Unused Memory 
(00004000-1FFFFFF0,10000000-FFFFFFFF)</B><BR>Accessing unused memory returns the 
recently pre-fetched opcode, ie. the 32bit opcode at $+8 in ARM state, or the 
16bit-opcode at $+4 in THUMB state, in the later case the 16bit opcode is 
mirrored across both upper/lower 16bits of the returned 32bit data.<BR>The same 
effect occurs on disabled WRAM (2000000h-3FFFFFFh), see Port 4000800h.<BR>Note: 
This is caused by the prefetch pipeline in the CPU itself, not by the external 
gamepak prefetch, ie. it works for code in RAM as well.<BR><BR><B>Reading from 
Unused or Write-Only I/O Ports</B><BR>Works like above unused memory when the 
entire 32bit memory fragment is Unused (eg. 0E0h) and/or Write-Only (eg. 
DMA0SAD). And otherwise, returns zero if the lower 16bit fragment is readable 
(eg. 04C=MOSAIC, 04E=NOTUSED/ZERO).<BR><BR><B>Reading from GamePak ROM when no 
Cartridge is inserted</B><BR>Because Gamepak uses the same signal-lines for both 
16bit data and for lower 16bit halfword address, the entire gamepak ROM area is 
effectively filled by incrementing 16bit values (Address/2 AND 
FFFFh).<BR><BR><B>Memory Mirrors</B><BR>Most internal memory is mirrored across 
the whole 24bit/16MB address space in which it is located: Slow On-board RAM at 
2XXXXXX, Fast In-Chip RAM at 3XXXXXXh, Palette RAM at 5XXXXXXh, VRAM at 
6XXXXXXh, and OAM at 7XXXXXXh. Even though VRAM is sized 96K (64K+32K), it is 
repeated in steps of 128K (64K+32K+32K, the two 32K blocks itself being mirrors 
of each other).<BR>BIOS ROM, Normal ROM Cartridges, and I/O area are NOT 
mirrored, the only exception is the undocumented I/O port at 4000800h (repeated 
each 64K).<BR>The 64K SRAM area is mirrored across the whole 32MB area at 
E000000h-FFFFFFFh, also, inside of the 64K SRAM field, 32K SRAM chips are 
repeated twice.<BR><BR><B>Writing 8bit Data to Video Memory</B><BR>Video Memory 
(BG, OBJ, OAM, Palette) can be written to in 16bit and 32bit units only. 
Attempts to write 8bit data (by STRB opcode) won't work:<BR>Writes to OBJ 
(6010000h-6017FFFh) (or 6014000h-6017FFFh in Bitmap mode) and to OAM 
(7000000h-70003FFh) are ignored, the memory content remains unchanged.<BR>Writes 
to BG (6000000h-600FFFFh) (or 6000000h-6013FFFh in Bitmap mode) and to Palette 
(5000000h-50003FFh) are writing the new 8bit value to BOTH upper and lower 8bits 
of the addressed halfword, ie. "[addr AND NOT 1]=data*101h".<BR><BR><B>Using 
Invalid Tile Numbers</B><BR>In Text mode, large tile numbers (combined with a 
non-zero character base setting in BGnCNT register) may exceed the available 64K 
of BG VRAM.<BR>On GBA and GBA SP, such invalid tiles are displayed as if the 
character data is filled by the 16bit BG Map entry value (ie. as vertically 
striped tiles). Above applies only if there is only one BG layer enable, with 
two or more layers, things are getting much more complicated: tile-data is then 
somehow derived from the other layers, depending on their priority order and 
scrolling offsets.<BR>On NDS (in GBA mode), such invalid tiles are displayed as 
if the character data is zero-filled (ie. as invisible/transparent 
tiles).<BR><BR><B>Accessing SRAM Area by 16bit/32bit</B><BR>Reading retrieves 
8bit value from specified address, multiplied by 0101h (LDRH) or by 01010101h 
(LDR). Writing changes the 8bit value at the specified address only, being set 
to LSB of (source_data ROR (address*8)).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=externalconnectors></A><FONT size=+2>&nbsp;External 
      Connectors</FONT></TD></TR></TBODY></TABLE><BR><B>External Connectors</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxgbagamepakbus">AUX GBA Game Pak 
Bus</A><BR><A href="http://nocash.emubase.de/gbatek.htm#auxdsgamecardslot">AUX 
DS Game Card Slot</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxlinkport">AUX Link Port</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxsoundheadphonesocketandbatterypowersupply">AUX 
Sound/Headphone Socket and Battery/Power Supply</A><BR><BR><B>Getting access to 
Internal Pins</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxopeningthegba">AUX Opening the 
GBA</A><BR><A href="http://nocash.emubase.de/gbatek.htm#auxmainboard">AUX 
Mainboard</A><BR><BR><B>More Internal Stuff</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutscpusignalsummary">Pinouts - CPU 
- Signal Summary</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutscpupinouts">Pinouts - CPU - 
Pinouts</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutsaudioamplifiers">Pinouts - 
Audio Amplifiers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutslcdcables">Pinouts - LCD 
Cables</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutspowerswitchesdcdcconvertersresetgenerators">Pinouts 
- Power Switches, DC/DC Converters, Reset Generators</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutswifi">Pinouts - Wifi</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pinoutsvarious">Pinouts - 
Various</A><BR><BR><B>Xboo Multiboot Cable</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxxboopctogbamultibootcable">AUX Xboo 
PC-to-GBA Multiboot Cable</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxxbooflashcardupload">AUX Xboo 
Flashcard Upload</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#auxxbooburstbootbackdoor">AUX Xboo 
Burst Boot Backdoor</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsxboo">DS Xboo</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxgbagamepakbus></A><FONT size=+2>&nbsp;AUX GBA Game Pak 
      Bus</FONT></TD></TR></TBODY></TABLE><BR><B>Game Pak Bus - 32pin cartridge 
slot</B><BR>The cartridge bus may be used for both CGB and GBA game paks. In GBA 
mode, it is used as follows:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Pin    Name    Dir  Expl.
 1      VDD     O    Power Supply 3.3V DC
 2      PHI     O    System Clock (selectable none, 4.19MHz, 8.38MHz, 16.78MHz)
 3      /WR     O    Write Select    ;\latched address to be incremented on
 4      /RD     O    Read Select     ;/rising edges of /RD or /WR signals
 5      /CS     O    ROM Chip Select ;-A0..A15 to be latched on falling edge
 6-21   AD0-15  I/O  lower 16bit Address    and/or  16bit ROM-data (see below)
 22-29  A16-23  I/O  upper 8bit ROM-Address   or    8bit SRAM-data (see below)
 30     /CS2    O    SRAM Chip Select
 31     /REQ    I    Interrupt request (/IREQ) or DMA request (/DREQ)
 32     GND     O    Ground 0V
</PRE></TD></TR></TBODY></TABLE>When accessing game pak SRAM, a 16bit address is 
output through AD0-AD15, then 8bit of data are transferred through 
A16-A23.<BR>When accessing game pak ROM, a 24bit address is output through 
AD0-AD15 and A16-A23, then 16bit of data are transferred through 
AD0-AD15.<BR>The 24bit address is formed from the actual 25bit memory address 
(byte-steps), divided by two (halfword-steps).<BR><BR><B>8bit-Gamepak-Switch 
(GBA, GBA SP only) (not DS)</B><BR>A small switch is located inside of the 
cartridge slot, the switch is pushed down when an 8bit cartridge is inserted, it 
is released when a GBA cartridge is inserted (or if no cartridge is 
inserted).<BR>The switch mechanically controls whether VDD3 or VDD5 are output 
at VDD35; ie. in GBA mode 3V power supply/signals are used for the cartridge 
slot and link port, while in 8bit mode 5V are used.<BR>The switch additionally 
drags IN35 to 3V when an 8bit cart is inserted, the current state of IN35 can be 
determined in GBA mode via Port 4000204h (WAITCNT), if the switch is pushed, 
then CGB mode can be activated via Port 4000000h (DISPCNT.3), this bit can be 
set ONLY by opcodes in BIOS region (eg. via CpuSet SWI function).<BR>In 8bit 
mode, the cartridge bus works much like for GBA SRAM, however, the 8bit /CS 
signal is expected at Pin 5, while GBA SRAM /CS2 at Pin 30 is interpreted as 
/RESET signal by the 8bit MBC chip (if any). In practice, this appears to result 
in 00h being received as data when attempting to read-out 8bit cartridges from 
inside of GBA mode.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxdsgamecardslot></A><FONT size=+2>&nbsp;AUX DS Game Card 
      Slot</FONT></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pin    Dir  Name  Connection in cartridge
  1   &gt;  -    GND   (ROM all unused Pins, EEPROM Pin 4 = VSS)
  2      Out  CLK   (4MB/s, ROM Pin 5, EEPROM Pin 6 = CLK)
  3   N  ?    ?     (ROM Pin 17) (Seems to be not connected in console)
  4   i  Out  /CS1  (ROM Pin 44) ROM Chipselect
  5   n  Out  /RES  (ROM Pin 42) Reset, switches ROM to unencrypted mode
  6   t  Out  /CS2  (EPROM Pin 1) EEPROM Chipselect
  7   e  In   IRQ   (GND)
  8   n  -    3.3V  (ROM Pins 2, 23, EEPROM Pins 3,7,8 = /W,/HOLD,VCC)
  9   d  I/O  D0    (ROM Pin 18)
  10  o  I/O  D1    (ROM Pin 19)
  11     I/O  D2    (ROM Pin 20)
  12  C  I/O  D3    (ROM Pin 21)
  13  0  I/O  D4    (ROM Pin 24)
  14  1  I/O  D5    (ROM Pin 25)
  15  -  I/O  D6    (ROM Pin 26, EEPROM Pin 2 = Q = Data EEPROM to NDS)
  16  0  I/O  D7    (ROM Pin 27, EEPROM Pin 5 = D = Data NDS to EEPROM)
  17  1  -    GND   (ROM all unused Pins, EEPROM Pin 4 = VSS)
</PRE></TD></TR></TBODY></TABLE><BR>Chipselect High-to-Low transitions are 
invoking commands, which are transmitted through data lines during next 
following eight CLK pulses, after the command transmission, further CLK pulses 
are used to transfer data, the data transfer ends at chipselect Low-to-High 
transition.<BR>Data should be stable during CLK=LOW period throughout CLK rising 
edge.<BR>Note: Supply Pins (1,8,17) are slightly longer than other 
pins.<BR><BR>The DS does also have a 32pin cartridge slot, that slot is used to 
run GBA carts in GBA mode, it can be also used as expansion port in DS 
mode.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxlinkport></A><FONT size=+2>&nbsp;AUX Link 
  Port</FONT></TD></TR></TBODY></TABLE><BR><B>Serial Link Port Pin-Out (GBA:"EXT" 
- GBA SP:"EXT.1")</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pin  Name  Cable
  1    VDD35 N/A       GBA Socket     GBA Plug   Old "8bit" Plug
  2    SO    Red       ___________    _________    ___________
  3    SI    Orange   |  2  4  6  |  / 2  4  6 \  |  2  4  6  |
  4    SD    Brown     \_1_ 3 _5_/   \_1_ 3 _5_/   \_1__3__5_/
  5    SC    Green         '-'           '-'
  6    GND   Blue      Socket Outside View / Plug Inside View
  Shield     Shield
</PRE></TD></TR></TBODY></TABLE>Note: The pin numbers and names are printed on 
the GBA mainboard, colors as used in Nintendo's AGB-005 and older 8bit 
cables.<BR><BR><B>Cable Diagrams (Left: GBA Cable, Right: 8bit Gameboy 
Cable)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Big Plug  Middle Socket  Small Plug    Plug 1         Plug 2
   SI _________________     ____ SI       SI ______  ______SI
   SO ____________SO   |__ | ___ SO       SO ______&gt;&lt;______SO
   GND____________GND______|____GND       GND_____________GND
   SD ____________SD____________ SD       SD               SD
   SC ____________SC____________ SC       SC _____________ SC
   Shield_______Shield_______Shield       Shield_______Shield
</PRE></TD></TR></TBODY></TABLE><BR><B>Normal Connection</B><BR>Just connect the 
plugs to the two GBAs and leave the Middle Socket disconnected, in this mode 
both GBAs may behave as master or slave, regardless of whether using big or 
small plugs.<BR>The GBA is (NOT ???) able to communicate in Normal mode with 
MultiPlay cables which do not have crossed SI/SO lines.<BR><BR><B>Multi-Play 
Connection</B><BR>Connect two GBAs as normal, for each further GBAs connect an 
additional cable to the Middle socket of the first (or further) cable(s), up to 
four GBAs may be connected by using up to three cables.<BR>The GBA which is 
connected to a Small Plug is master, the slaves are all connected to Large 
Plugs. (Only small plugs fit into the Middle Socket, so it's not possible to 
mess up something here).<BR><BR><B>Multi-Boot Connection</B><BR>MultiBoot 
(SingleGamepak) is typically using Multi-Play communication, in this case it is 
important that the Small plug is connected to the master/sender (ie. to the GBA 
that contains the cartridge).<BR><BR><B>Non-GBA Mode Connection</B><BR>First of 
all, it is not possible to link between 32bit GBA games and 8bit games, parts 
because of different cable protocol, and parts because of different signal 
voltages.<BR>However, when a 8bit cartridge is inserted (the GBA is switched 
into 8bit compatibility mode) it may be connected to other 8bit games 
(monochrome gameboys, CGBs, or to other GBAs which are in 8bit mode also, but 
not to GBAs in 32bit mode).<BR>When using 8bit link mode, an 8bit link cable 
must be used. The GBA link cables won't work, see below modification 
though.<BR><BR><B>Using a GBA 32bit cable for 8bit communication</B><BR>Open the 
middle socket, and disconnect Small Plugs SI from GND, and connect SI to Large 
Plugs SO instead. You may also want to install a switch that allows to switch 
between SO and GND, the GND signal should be required for MultiPlay 
communication only though.<BR>Also, cut off the plastic ledge from the plugs so 
that they fit into 8bit gameboy sockets.<BR><BR><B>Using a GBA 8bit cable for 
32bit communication</B><BR>The cable should theoretically work as is, as the 
grounded SI would be required for MultiPlay communication only. However, 
software that uses SD for Slave-Ready detection won't work unless when adding a 
SD-to-SD connection (the 8bit plugs probably do not even contain SD pins 
though).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxsoundheadphonesocketandbatterypowersupply></A><FONT 
      size=+2>&nbsp;AUX Sound/Headphone Socket and Battery/Power 
  Supply</FONT></TD></TR></TBODY></TABLE><BR><B>GBA and NDS and NDS-Lite: Stereo 
Sound Connector (3.5mm, female)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Tip     Audio Left         ___ ___ _____+-----------+
  Middle  Audio Right       (___|___|_____|           |
  Base    Ground              L   R   GND +-----------+
</PRE></TD></TR></TBODY></TABLE>The NDS socket doesn't fully match regular 3.5mm 
plugs, one needs to cut-off a portion of the DS case to be able to fully insert 
the plug, which still requires a lot of pressure, furthermore, when fully 
inserted, left/right become shortcut to mono, so one needs to pull-back the plug 
a bit to gain stereo output.<BR><BR><B>GBA SP and NDS - Power/Headphone Socket 
(EXT.2)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pin SP   NDS  Expl.
  1   P31  SL   Audio LOUT                          _____________
  2   P32  VIN  Supply Input (DC 5.2V)           SW| 5   ___   1 |SL
  3   P33  SR   Audio ROUT                         | ----   ---- |
  4   P34  SG   Audio GND (via 100uF to GND)       |_6__4   3__2_|
  5   P35  SW   Audio Speaker Disable (GND=Dis)    GND SG\_/SR VIN
  6        GND  Supply GND
  Shield        GND
</PRE></TD></TR></TBODY></TABLE>External power input is used to charge the 
built-in battery, it cannot be used to run the SP without that 
battery.<BR><BR><B>NDS-Lite - Power Socket</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pin  Expl.                                          __________
  1    Supply Input (DC 5.2V)                        /  ======  \
  2    Supply GND                                GND |___2__1___| VIN
</PRE></TD></TR></TBODY></TABLE><BR><B>External Power Supply</B><BR>GBA: DC 3.3V 
(no separate power socket, requires 2xAA-battery-shaped adapter)<BR>GBA-SP/NDS: 
DC 5.2V (or DC 5V) (special connector on power/headphone socket)<BR>NDS-Lite: DC 
5.2V (or DC 5V) (another special connector on power socket)<BR><BR><B>Internal 
Battery Supply</B><BR>GBA: 2xAA (3V)<BR>GBA-SP: Li-ion 3.7V, 600mAh (built-in, 
recharge-able)<BR>NDS: Li-ion 3.7V, 850mAh (built-in, 
recharge-able)<BR>NDS-Lite: Li-ion 3.7V, 1000mAh (built-in, 
recharge-able)<BR><BR><B>Using PC +5V DC as Power Supply</B><BR>Developers whom 
are using a PC for GBA programming will probably want to use the PC power supply 
(gained from disk drive power supply cable) for the GBA as well rather than 
dealing with batteries or external power supplies.<BR>GBA: To lower the voltage 
to approximately 3 Volts use two diodes, type 1N 4004 or similar, the ring 
printed onto the diodes points towards the GBA side, connected as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  PC +5V (red)   --------|&gt;|---|&gt;|--------  GBA BT+
  PC GND (black) -------------------------  GBA BT-
</PRE></TD></TR></TBODY></TABLE>GBA SP and DS: Works directly at +5V connected 
to EXT.2 socket (not to the internal battery pins), without any 
diodes.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxopeningthegba></A><FONT size=+2>&nbsp;AUX Opening the 
      GBA</FONT></TD></TR></TBODY></TABLE><BR>Since Nintendo uses special screws with 
Y-shaped heads to seal the GBA (as well as older 8bit gameboys), it's always a 
bit difficult to loosen these screws.<BR><BR><B>Using Screwdrivers</B><BR>One 
possible method is to use a small flat screwdriver, which might work, even 
though it'll most likely damage the screwdriver.<BR>Reportedly, special Y-shaped 
screwdrivers for gameboys are available for sale somewhere (probably not at your 
local dealer, but you might find some in the internet or 
elsewhere).<BR><BR><B>Destroying the Screws</B><BR>A more violent method is to 
take an electric drill, and drill-off the screw heads, this might also slightly 
damage the GBA plastic chase, also take care that the metal spoons from the 
destroyed screws don't produce shortcuts on the GBA mainboard.<BR><BR><B>Using a 
selfmade Screwdriver</B><BR>A possible method is to take a larger screw (with a 
normal I-shaped, or X-shaped head), and to cut the screw-tip into Y-shape, 
you'll then end up with an "adapter" which can be placed in the middle between a 
normal screwdriver and gameboy screws.<BR>Preferably, first cut the screw-tip 
into a shape like a "sharp three sided pyramid", next cut notches into each 
side. Access to a grinding-machine will be a great benefit, but you might get it 
working by using a normal metal-file as well.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxmainboard></A><FONT size=+2>&nbsp;AUX 
  Mainboard</FONT></TD></TR></TBODY></TABLE><BR>Other possibly useful signals on 
the mainboard...<BR><BR><B>FIQ Signal</B><BR>The FIQ (Fast Interrupt) signal 
(labeled FIQ on the mainboard) could be used as external interrupt (or debugging 
break) signal.<BR>Caution: By default, the FIQ input is directly shortcut to 
VDD35 (+3V or +5V power supply voltage), this can be healed by scratching off 
the CL1 connection located close to the FIQ pin (FIQ still appears to have an 
internal pull-up, so that an external resistor is not required).<BR>The GBA BIOS 
rejects FIQs if using normal ROM cartridge headers (or when no cartridge is 
inserted). When using a FIQ-compatible ROM header, Fast Interrupts can be then 
requested by pulling FIQ to ground, either by a push button, or by remote 
controlled signals.<BR><BR><B>RESET Signal</B><BR>The RESET signal (found on the 
mainboard) could be used to reset the GBA by pulling the signal to ground for a 
few microseconds (or longer). The signal can be directly used (it is not 
shortcut to VDD35, unlike FIQ).<BR>Note: A reset always launches Nintendo's 
time-consuming and annoying boot/logo procedure, so that it'd be recommend to 
avoid this "feature" when possible.<BR><BR><B>Joypad Signals</B><BR>The 10 
direction/button signals are each directly shortcut to ground when pressed, and 
pulled up high otherwise (unlike 8bit gameboys which used a 2x4 keyboard 
matrix), it'd be thus easy to connect a remote keyboard, keypad, joypad, or 
read-only 12bit parallel port.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutscpusignalsummary></A><FONT size=+2>&nbsp;Pinouts - CPU 
      - Signal Summary</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy CPU 
Signal Summary</B><BR>Cart Bus: D0-D7, A0-A15, /CS, /RD, /WR (different usage in 
GBA/DMG mode)<BR>WRAM Bus: WA0-WA16, WD0-WD15, /WLB, /WUB, /WWE, /WOE (used in 
GBA mode only)<BR>LCD Bus : LDR1-5, LDG1-5, LDB1-5, DCK, LP, PS, SPL, CLS, SPS, 
MOD, REVC<BR>Joypad: TP0-3 (Buttons), TP4-7 (Directions), TP8-9 (L/R-Buttons, 
via R43/R44)<BR>Serial Link: SC, SD (aka P14?), SI, SO - Audio: SO1-2, 
Vin<BR>Other: CK1-2, PHI, IN35, VCNT5, /FIQ (via CL1 to VDD3), /RESET (IN), /RES 
(OUT)<BR>Supply: VDD35, VDD3, VDD2, GND (some are probably undoc inputs)<BR>GBA 
SP: Same as GBA, plus VDD1, plus duplicated supply pins, plus pin 
152.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutscpupinouts></A><FONT size=+2>&nbsp;Pinouts - CPU - 
      Pinouts</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy CPU Pinouts (CPU 
AGB)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 VDD3  17 D0   33 A0    49 WA4   65 VDD2  81 WD9   97 LDB5   113 CK1
  2 IN35  18 A15  34 /CS   50 WA5   66 WD5   82 WD1   98 LDB4   114 CK2
  3 TP8   19 A14  35 /RD   51 WA6   67 WD13  83 /WOE  99 LDB3   115 VDD2
  4 TP0   20 A13  36 /WR   52 WA7   68 WD6   84 DCK   100 LDB2  116 GND
  5 TP1   21 A12  37 PHI   53 /WLB  69 WD14  85 LP    101 LDB1  117 VDD2
  6 SO1   22 A11  38 VDD35 54 /WUB  70 WD7   86 PS    102 GND   118 VCNT5
  7 SO2   23 A10  39 GND   55 /WWE  71 WD15  87 LDR5  103 VDD3  119 TP9
  8 Vin   24 A9   40 SC    56 WA8   72 WD8   88 LDR4  104 SPL   120 TP6
  9 /RES  25 A8   41 SD    57 WA9   73 WD16  89 LDR3  105 CLS   121 TP5
  10 D7   26 A7   42 SI    58 WA10  74 WA16  90 LDR2  106 SPS   122 TP7
  11 D6   27 A6   43 SO    59 WA11  75 WD12  91 LDR1  107 MOD   123 TP4
  12 D5   28 A5   44 VDD2  60 WA12  76 WD4   92 LDG5  108 REVC  124 /FIQ
  13 D4   29 A4   45 WA0   61 WA13  77 WD11  93 LDG4  109 GNDed 125 /RESET
  14 D3   30 A3   46 WA1   62 WA14  78 WD3   94 LDG3  110 GNDed 126 TP2
  15 D2   31 A2   47 WA2   63 WA15  79 WD10  95 LDG2  111 GNDed 127 TP3
  16 D1   32 A1   48 WA3   64 GND   80 WD2   96 LDG1  112 GNDed 128 GND
</PRE></TD></TR></TBODY></TABLE><BR><B>GBA SP CPU Pinouts (CPU AGB B)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 IN35   21 D0    41 A0    61 WA4   81 WD13  101 GND   121 LDB4  141 GND
  2 TP8    22 A15   42 /CS   62 WA5   82 WD6   102 VDD1  122 LDB3  142 VDD3
  3 TP0    23 A14   43 /RD   63 WA6   83 WD14  103 GND   123 LDB2  143 GND
  4 TP1    24 A13   44 /WR   64 WA7   84 WD7   104 VDD3  124 LDB1  144 VCNT5
  5 SO1    25 A12   45 PHI   65 /WLB  85 WD15  105 DCK   125 GND   145 TP9
  6 SO2    26 A11   46 VDD35 66 /WUB  86 WD8   106 LP    126 VDD3  146 TP6
  7 Vin    27 GND   47 GND   67 GND   87 WD16  107 PS    127 SPL   147 TP5
  8 VDD1   28 VDD35 48 SC    68 VDD2  88 WA16  108 LDR5  128 CLS   148 TP7
  9 GND    29 A10   49 SD    69 /WWE  89 VDD2  109 LDR4  129 SPS   149 TP4
  10 VDD35 30 A9    50 SI    70 WA8   90 GND   110 LDR3  130 MOD   150 /FIQ
  11 /RES  31 A8    51 SO    71 WA9   91 WD12  111 LDR2  131 REVC  151 /RESET
  12 D7    32 A7    52 VDD35 72 WA10  92 WD4   112 LDR1  132 GND   152 ?
  13 D6    33 A6    53 GND   73 WA11  93 WD11  113 LDG5  133 GND   153 TP3
  14 D5    34 A5    54 VDD1  74 WA12  94 WD3   114 LDG4  134 GND   154 TP2
  15 D4    35 A4    55 GND   75 WA13  95 WD10  115 LDG3  135 GND   155 VDD3
  16 D3    36 GND   56 VDD2  76 WA14  96 WD2   116 LDG2  136 VDD1  156 GND
  17 D2    37 VDD35 57 WA0   77 WA15  97 WD9   117 LDG1  137 GND
  18 GND   38 A3    58 WA1   78 GND   98 WD1   118 GND   138 CK1
  19 VDD35 39 A2    59 WA2   79 VDD2  99 /WOE  119 VDD3  139 CK2
  20 D1    40 A1    60 WA3   80 WD5   100 VDD2 120 LDB5  140 VDD2
</PRE></TD></TR></TBODY></TABLE>Pin 152 seems to be not connected on the 
mainboard, maybe an undoc output.<BR><BR><B>NDS CPU Pinouts</B><BR>Unknown. The 
CPU is hidden underneath of the DS Cartridge Slot - and to the worst, the CPU 
Pins are hidden underneath of the CPU itself.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutsaudioamplifiers></A><FONT size=+2>&nbsp;Pinouts - Audio 
      Amplifiers</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy Audio 
Amplifier (AMP AGB IR3R60N) (U6)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1   2   3   4   5   6   7   8   9   10  11  12   13   14   15   16   17  18
  C38 FR1 FR2 FL1 FL2 GND RIN LIN C39 VOL SW  VDD5 LOUT VCC3 ROUT VCC3 SP  GND
</PRE></TD></TR></TBODY></TABLE>SW=Headphone Switch (grounded when none 
connected).<BR><BR><B>GBA SP Audio Amplifier (uses AMB AGB IR3R60N, too) 
(U3)</B><BR>Same connection as in GBA, except that pin14/16 connect to VR21 
(instead VCC3), and pin1/9 connect to different capacitors.<BR><BR><B>NDS - 
National Semiconductor LM4880M Dual 250mW Audio Power Amplifier (U12)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1-OUT A  2-IN A  3-BYPASS  4-GND  5-SHUTDOWN  6-IN B  7-OUT A  8-VDD.VQ5
</PRE></TD></TR></TBODY></TABLE>NDS-Lite: No external amplifier (Mitsumi 3205B 
Powermanagment Device contains internal amplifier).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutslcdcables></A><FONT size=+2>&nbsp;Pinouts - LCD 
      Cables</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy Display 
Socket</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 ?     6 GND    11 LDR2   16 LDG2   21 LDB3   26 SPS     31 P2-VSS  36 V4
  2 VSHD  7 VSHD   12 LDR1   17 LDG1   22 LDB2   27 ?       32 P2-VCC  37 V3
  3 DCK   8 LDR5   13 LDG5   18 GND    23 LDB1   28 MOD     33 ?       38 V2
  4 LP    9 LDR4   14 LDG4   19 LDB5   24 SPL    29 VCOM    34 VDD5    39 V1
  5 PS    10 LDR3  15 LDG3   20 LDB4   25 CLS    30 P2-VEE  35 GND     40 V0
</PRE></TD></TR></TBODY></TABLE><BR><B>GBA SP Display Socket</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 VSHD 5 VSHD  9 LDR3   13 LDG4  17 GND   21 LDB2  25 SPS   29 P2VSS 33 U83
  2 DCK  6 GND   10 LDR2  14 LDG3  18 LDB5  22 LDB1  26 MOD   30 COM   34 VDD5
  3 LP   7 LDR5  11 LDR1  15 LDG2  19 LDB4  23 SPL   27 REVC  31 VDD5
  4 PS   8 LDR4  12 LDG5  16 LDG1  20 LDB3  24 CLS   28 P2VDD 32 GND
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS Upper/Lower Display Sockets</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ___NDS upper screen/upper backlight/speakers socket (P3)_____________________
  1-SPLO 7-PS2   13-LDR2  19-GND   25-LDG2  31-LDB2  37-MOD2  43-VDD15  49-SPRO
  2-SPLO 8-REV2  14-LDR1  20-DCLK2 26-LDG1  32-LDB1  38-GND   44-VDD-5  50-GND
  3-SSC2 9-GND   15-LDR0  21-GND   27-LDG0  33-LDB0  39-VDD5  45-VDD-10 51-GND
  4-ASC2 10-LDR5 16-LS2   22-LDG5  28-LDB5  34-GCK2  40-VDD10 46-LEDC2
  5-GND  11-LDR4 17-VSHD  23-LDG4  29-LDB4  35-GSP2  41-COM2  47-LEDA2
  6-SPL2 12-LDR3 18-DISP1 24-LDG3  30-LDB3  36-GND   42-GND   48-SPRO
  ___NDS lower screen socket (P4)______________________________________________
  1-SSC1 6-REV1  11-LDR2  16-DISP0 21-LDG4  26-LDB5  31-LDB0  36-GND  41-VDD15
  2-ASC1 7-GND   12-LDR1  17-SPL1  22-LDG3  27-LDB4  32-GCK1  37-?    42-VDD10
  3-GND  8-LDR5  13-LDR0  18-DCLK1 23-LDG2  28-LDB3  33-GSP1  38-VDD5 43-GND
  4-?    9-LDR4  14-LS1   19-GND   24-LDG1  29-LDB2  34-VSHD  39-COM1 44-VDD-5
  5-PS1  10-LDR3 15-VSHD  20-LDG5  25-LDG0  30-LDB1  35-MOD1  40-GND  45-VDD-10
  ___NDS lower backlight socket (P5)____   ___NDS touchscreen socket (P6)______
  1:LEDA1  2:LEDA1  3:LEDC1  4:LEDC1       1:Y-    2:X-    3:Y+    4:X+
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS-Lite Upper/Lower Display 
Sockets</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ___NDS-Lite upper screen/upper backlight/speakers socket (P3)________________
  1-VDD-5 6-MOD    11-LD2xx 16-LD2xx 21-LD2xx 26-LD2xx 31-LS   36-GND   41-SPRO
  2-VDD10 7-GSP    12-LD2xx 17-LD2xx 22-LD2xx 27-LD2xx 32-VSHD 37-COM2  42-SG
  3-VDD5  8-GCK    13-LD2xx 18-GND   23-LD2xx 28-GND   33-GND  38-LEDA2 43-SG
  4-GND   9-LD2xx  14-LD2xx 19-LD2xx 24-LD2xx 29-DCLK  34-xx2? 39-LEDC2 44-SPLO
  5-VSHD  10-LD2xx 15-LD2xx 20-LD2xx 25-LD2xx 30-SPL   35-REV  40-SPRO  45-SPLO
  ___NDS-Lite lower screen/lower backlight (P4)________________________________
  1-VDD-5 6-MOD    11-LD1xx 16-LD1xx 21-LD1xx 26-LD1xx 31-LS   36-GND
  2-VDD10 7-GSP    12-LD1xx 17-LD1xx 22-LD1xx 27-LD1xx 32-VSHD 37-COM1
  3-VDD5  8-GCK    13-LD1xx 18-GND   23-LD1xx 28-GND   33-GND  38-LEDA1
  4-GND   9-LD1xx  14-LD1xx 19-LD1xx 24-LD1xx 29-DCLK  34-xx1? 39-LEDC1
  5-VSHD  10-LD1xx 15-LD1xx 20-LD1xx 25-LD1xx 30-SPL   35-REV
  ___NDS-Lite touchscreen socket (P6)______   ___NDS-Lite white coax (P12)_____
  1:X-  2:Y-  3:X+  4:Y+                      Center:MICIN  Shield:GND
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutspowerswitchesdcdcconvertersresetgenerators></A><FONT 
      size=+2>&nbsp;Pinouts - Power Switches, DC/DC Converters, Reset 
      Generators</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy Power Switch 
(2-position slider, with two common pins)</B><BR><B>GBA SP Power Switch (same as 
GBA)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 via resistor to GND (OFF)
  2 VS (BT+) (ON)
  C VCC (to board)
</PRE></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy Cartridge Slot Switch 
(integrated 4pin micro switch)</B><BR><B>GBA SP Cartridge Slot Switch (separate 
4pin micro switch)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  C1 VDD35  (to S2 when PRESSED, to S1 when RELEASED)
  S1 VDD3   (to C2 when PRESSED, to C1 when RELEASED)
  C2 IN35   (to S1 when PRESSED)
  S2 VDD5   (to C1 when PRESSED)
</PRE></TD></TR></TBODY></TABLE>Pressed=8bit DMG/MGB/CGB cart, Released=32bit 
GBA cart (or no cart inserted)<BR>GBA: switch integrated in cart socket, GBA-SP: 
separate switch next to socket.<BR><BR><B>Advance Gameboy Power Controller (M 
121 514X) (U4)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1-VIN    2-VOUT5  3-CSS5    4-VDRV5  5-GND    6-VDRV3    7-CSS3    8-VOUT3
  9-VCNT5  10-CSCP  11-REGEXT 12-VDD3  13-VDD2  14-/RESET  15-LOWBAT 16-VDD13
</PRE></TD></TR></TBODY></TABLE>/RESET is passed to the CPU, and then forwarded 
to /RES pin on cart slot.<BR><BR><B>Advance Gameboy LCD Regulator (AGB-REG 
IR3E09N) (U3)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1  2  3    4      5   6   7   8   9   10   11  12  13  14  15  16   17     18
  ?  ?  REVC U3-COM V0  V1  ?   ?   ?   GND  ?   V2  ?   V3  V4  VDD5 U3-VDD ?
</PRE></TD></TR></TBODY></TABLE><BR><B>GBA SP Power Controller 1 (S6403 AU227 
9276) (U4)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1-VCC    2-SCP1   3-SCP2 4-VDRV3 5-VOUT3/VDD3 6-VDD2  7-VOUT1/VDD1  8-VDRV1
  9-LOWBAT 10-VCNT5 11-LS5 12-?    13-GND       14-?    15-VOUT5/VDD5 16-VDRV5
</PRE></TD></TR></TBODY></TABLE><BR><B>GBA SP Power Controller 2 (2253B 2808) 
(U5)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1-TIN     2-U5C3     3-ADJ  4-U5VDD  5-VIN   6-?    7-U57  8-?
  9-to-C29  10-to-C30  11-?   12-GND   13-VS   14-S-  15-S+  16-U5OUT
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS Powermanagment Device (Mitsumi 3152A) 
(U3)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 R50-EXTB+        17               33 LEDC1           49 VCNT5
  2 R39-ORANGE       18               34 GND             50
  3 GND              19 VQ5           35 LEDC2           51 RST
  4                  20               36                 52
  5 Rxx-Q4           21               37 U10-LEDA2       53
  6 INS+             22 GND           38                 54
  7 INS-             23 VQ5           39 MIC.C53-AIN     55 VQ5
  8                  24               40 MIC.TSC.AUX     56 R24-SR
  9 VDET             25 VDD3.3        41 GND             57
  10 PVDD            26 GND           42 R38-RED         58 R22-SL
  11                 27 CL60-VDD3.3   43 R37-GREEN       59 GND
  12 PWSW            28 VSHD          44 VDD3.3          60 VR3.PIN2
  13                 29               45 PWM.SPI.CLK     61
  14 GND             30 VDD5          46 PWM.SPI.D       62
  15 GND             31 U9-LEDA1      47 PWM.SPI.Q       63
  16 VQ5             32               48 PWM.SPI.SEL     64 GND
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS-LITE Powermanagment Device (Mitsumi 
3205B) (U3)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 SW               17               33 LEDC1           49 VCNT5
  2 R50-EXTB+        18               34 GND             50
  3 R39-ORANGE       19 VQ5           35 LEDC2           51 RST
  4 GND              20               36                 52
  5                  21               37 U10-LEDA2       53
  6 R30-Q4           22 GND           38                 54
  7 INS+             23 VQ5           39 MIC.C53-AIN     55 CL63-VQ5
  8 INS-             24               40 MIC.TSC.AUX     56 R24-SR
  9 VDET             25 VDD3.3        41 GND             57 SPRO
  10 PVDD            26 GND           42 R38-RED         58 SPLO
  11                 27 CL60-VDD3.3   43 R37-GREEN       59 R22-SL
  12 PWSW            28 VSHD          44 VDD3.3          60 GND
  13 GND             29               45 PWM.SPI.CLK     61 R79-VR3.PIN2
  14 GND             30 VDD5          46 PWM.SPI.D       62
  15 GND             31 U9-LEDA1      47 PWM.SPI.Q       63
  16 VQ5             32               48 PWM.SPI.SEL     64
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS-LITE Power Switch</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 PWSW (grounded when switch is pulled)
  2 GND
  3 GND
  4 NC? (grounded when switch is not pulled)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutswifi></A><FONT size=+2>&nbsp;Pinouts - 
  Wifi</FONT></TD></TR></TBODY></TABLE><BR><B>NDS RFU Daughter Board (Firmware 
FLASH, Wifi BB/RF Chips)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 N/A      6 FMW.CLK    11 ENABLE 16 RX.DTA? 21 BB./CS     26 22MHz   31 GND
  2 GND      7 FMW./SEL   12 GND    17 TX.MAIN 22 RF./CS     27 GND     32 GND
  3 high?    8 FMW.DTA.Q  13 GND    18 GND     23 BB.RF.CLK  28 VDD3.3  33 GND
  4 RXTX.ON  9 FMW.DTA.D  14 TX.ON  19 TX.CLK  24 BB.RF.RD   29 VDD1.8
  5 FMW./WP  10 FMW./RES  15 RX.ON  20 TX.DTA  25 BB.RF.WR   30 GND
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS-Lite RFU Daughter Board (Firmware 
FLASH, Wifi BB/RF Chip)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 GND      6 GND      11 BB.RF.WR  16 VDD3.3  21 hi?       26 FMW.Q
  2 lo?      7 hi?      12 BB.RF.CLK 17 GND     22 FMW./RES  27 FMW./WP
  3 hi?      8 hi?      13 GND       18 RF./CS  23 GND       28 FMW./CS
  4 hi?      9 GND      14 hi?       19 hi?     24 FMW.CLK   29 hi?
  5 hi?      10 hi?     15 GND       20 BB./CS  25 FMW.D     30 GND
</PRE></TD></TR></TBODY></TABLE><BR><B>Wifi RF Chip: RF9008, 0441, E0121Q (32 
pin)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1       5       9       13      17         21 RF.CLK  25        29
  2       6       10      14 GND  18         22         26        30
  3       7       11      15      19 RF.RD   23         27        31
  4       8       12      16      20 RF./CS  24         28        32
</PRE></TD></TR></TBODY></TABLE>Pin19 RF.RD (oops, should be WR, maybe I've 
exchanged RD-WR?)<BR>Pin20 RF./CS (via 10ohm)<BR>Pin21 RF.CLK (via 
10ohm)<BR><BR><B>Wifi BB Chip: Mitsumi, Japan, 4418, MM3155 (48 pins)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 GND   7       13 GND     19      25       31         37 TX.MAIN 43
  2       8       14         20      26       32 BB./CS  38 RX.DTA? 44
  3       9       15 BB.CLK  21      27       33 TX.DTA  39 RX.ON   45 GND
  4       10      16 BB.WR   22      28 RST   34 RXTX.ON 40 TX.ON   46
  5       11      17 BB.RD   23      29       35 TX.CLK  41         47
  6       12      18 22MHz   24      30       36         42         48
</PRE></TD></TR></TBODY></TABLE>Pin15 BB.CLK (via 10ohm to RFU.23)<BR>Pin16 
BB.WR (RFU.25)<BR>Pin17 BB.RD (RFU.24)<BR>Pin18 22MHz (via 50ohm)<BR>Pin28 RST 
(same as FMW./RES)<BR>Pin32 BB./CS (RFU.21)<BR><BR><B>NDS-LITE BB/RF-Chip 
Mitsumi MM3218 (56 pins)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1-    8-GND   15-    22-GND 29-    36-    43-    50-
  2-GND 9-      16-    23-    30-    37-    44-    51-
  3-    10-GND  17-    24-    31-    38-    45-    52-
  4-    11-GND  18-    25-    32-    39-GND 46-    53-
  5-    12-GND  19-    26-    33-    40-    47-    54-
  6-    13-     20-    27-    34-    41-    48-    55-
  7-    14-     21-    28-    35-    42-    49-GND 56-
</PRE></TD></TR></TBODY></TABLE><BR><B>TX Signal/Timing Chart (Host 
Game)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RX.DTA?  __________________________________________________________
  RXTX.ON  __-----------------------_________________________________
  RX.ON    __---_______-------------_________________________________
  TX.ON    _____-------______________________________________________
  TX.MAIN  ________----______________________________________________
  TX.CLK   _____#__####______________________________________________
  TX.DTA   _____#__####______________________________________________
</PRE></TD></TR></TBODY></TABLE>This example shows a host sending beacons. The 
pre-beacon receive period is probably to sense conflicts with other 
transmitters. The post-beacon receive period is to get responses from other 
players. The two transmit parts are: The hardware header, followed by inactivity 
on the tx pins during the rest of the preamble period, then followed by the 
actual IEEE frame. The rest of the time is spend in idle mode to reduce power 
consumption.<BR><BR><B>RX Signal/Timing Chart (Join Game)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RX.DTA?  __________________________________________________________
  RXTX.ON  -----------------------------------------------______-----
  RX.ON    -----------------------------------------------_________--
  TX.ON    __________________________________________________________
  TX.MAIN  __________________________________________________________
  TX.CLK   __________________________________________________________
  TX.DTA   _______________________________________________---________
</PRE></TD></TR></TBODY></TABLE>This example shows a client trying to receive 
beacons, so most of the time is spent in receive mode (the short idle periods 
are probably occuring when it is switching to another channel). Once when it has 
associated with a host, the client may spend more time in idle mode, and needs 
to be in receive mode only when expecting to receive beacons or other 
data.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pinoutsvarious></A><FONT size=+2>&nbsp;Pinouts - 
    Various</FONT></TD></TR></TBODY></TABLE><BR><B>Advance Gameboy 256Kbytes RAM 
128Kx16bit (NEC D442012LGY-B85x-MJH) (wide)</B><BR><B>GBA SP 256Kbytes RAM 
128Kx16bit (F 82D12160-10FN) (square)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 A15   7 A9    13 IC    19 A6   25 A0   31 D2   37 VCC  43 D15
  2 A14   8 A8    14 /UB   20 A5   26 /CE1 32 D10  38 D5   44 D8
  3 A13   9 NC    15 /LB   21 A4   27 GND  33 D3   39 D13  45 D16
  4 A12   10 NC   16 NC    22 A3   28 /OE  34 D11  40 D6   46 GND
  5 A11   11 /WE  17 NC    23 A2   29 D1   35 D4   41 D14  47 NC
  6 A10   12 CE2  18 A7    24 A1   30 D9   36 D12  42 D7   48 A16
</PRE></TD></TR></TBODY></TABLE>Connection in GBA and GBA SP: IC-GND, /CE1-GND, 
CE2-VDD2, VCC-VDD2, Pin16-VDD2, the other NC pins seem to be actually not 
connected, all other pins connect to the corresponding Wxx CPU pins. Note: Both 
GBA and GBA SP have soldering points for wide (12x18mm) and square (12x14mm) 
RAMs, so either could be used.<BR>The GBA additionally contains 32K built-in 
WRAM, and built-in VRAM, so the above 256K RAM chip is probably not used in 8bit 
classic/color gameboy mode.<BR><BR><B>Advance Gameboy Schematic 
Fragments</B><BR>P2-VSS = VDD-15<BR>VIN = VCC3 via R33<BR>REGEXT (on my modified 
board, REGEXT underneath of my diodes)<BR>/RES (OUT) (via R40)<BR>/CS (via 
R39)<BR>/WR (via R38)<BR>SC (via Rxx)<BR>SD (via Rxx)<BR>SI (via Rxx)<BR>SO (via 
Rxx)<BR>DCK (via R36)<BR>A-GND via CP4 (100uF) to GND (used speaker, and on 
headphone socket)<BR><BR><B>GBA SP Schematic Fragments</B><BR>P2VDD = 
VDD13<BR>P2VSS = VDD15<BR>/RES via R46<BR>/CS via R45<BR>/WR via R44<BR>DCK via 
R20<BR>VS=BT+<BR>In my repaired GBA-SP: CK1 test-point is disconnected (instead 
GND'ed).<BR>In my repaired GBA-SP: broken oscillator replaced<BR>In my repaired 
GBA-SP: broken r1 1mOhm replaced (near oscillator)<BR>In my repaired GBA-SP: 
broken EXT2 socket metal-spring/snapper removed<BR>CL1 FIQ (near SW4)<BR>CL2 
?<BR>CL3 ?<BR>CL4 VOUT1/VDD1 (near U4)<BR>CL5 VOUT3/VDD3 (near U4)<BR>CL6 
VOUT5/VDD5 (near U4)<BR>DL1-red (power low) ---R32--Q4--R6--<BR>DL2-green (power 
good) ---Q6--LOWBAT/R34-VDD3<BR>DL3-orange (charge) 
--R24--Q2--VIN/U57<BR>P2VDD--VDD13<BR>P2VSS--VDD15<BR>S+ and S- are (almost) 
shortcut by R23 (1.0 ohm)<BR>S+ via Q1 to VIN<BR>VS via D1 to S-<BR>A-GND via 
CP1 (100uF) to GND<BR>U4 pin 12 to r6 (towards red led)<BR>U4 pin 14 to D6---to 
U7<BR>SC (CPU pin48) with R7 100K ohm pullup to VDD35<BR>P35 via Q11 to SW 
(speaker disable)<BR><BR><B>GBA SP Backlight-Button Schematic 
(U6,U8,Q12)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>        ______                _____
  GND--|1 U8 6|-- U85        |     |--VDD5
  U82--|2    5|-- U85    U61-| Q12 |         U83  ------&gt; to display
  U83--|3____4|-- U82        |_____|--Q12B   Q12B &lt;------ from button
  U61--|1 U6 8|--VDD5    (X)---R51--VDD5    (X)---C70--GND
  U62--|2    7|--VDD5    U62---R49--VDD5    U61---R40--GND
  U62--|3    6|--(X)     Q12B--R39--VDD5    U82---R38--GND
  GND--|4____5|--NC?     Q12B--C69--VDD5    U85---R50--U62
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxxboopctogbamultibootcable></A><FONT size=+2>&nbsp;AUX Xboo 
      PC-to-GBA Multiboot Cable</FONT></TD></TR></TBODY></TABLE><BR>Below describes 
how to connect a PC parallel port to the GBA link port, allowing to upload small 
programs (max 256 KBytes) from no$gba's Utility menu into real GBAs.<BR><BR>This 
is possible because the GBA BIOS includes a built-in function for downloading 
&amp; executing program code even when no cartridge is inserted. The program is 
loaded to 2000000h and up in GBA memory, and must contain cartridge header 
information just as for normal ROM cartridges (nintendo logo, checksum, etc., 
plus some additional multiboot info).<BR><BR><B>Basic Cable 
Connection</B><BR>The general connection is very simple (only needs four wires), 
the only problem is that you need a special GBA plug or otherwise need to solder 
wires directly to the GBA mainboard (see Examples below).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GBA  Name  Color                 SUBD CNTR Name
  2    SO    Red     ------------- 10   10   /ACK
  3    SI    Orange  ------------- 14   14   /AUTOLF
  5    SC    Green   ------------- 1    1    /STROBE
  6    GND   Blue    ------------- 19   19   GND
</PRE></TD></TR></TBODY></TABLE>Optionally, also connect the following signals 
(see notes below):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4    SD    Brown   ------------- 17   36   /SELECT  (double speed burst)
  3    SI    Orange  ----[===]---- 2..9 2..9 D0..7    (pull-up, 560 Ohm)
  5    SC    Green   ----[===]---- 2..9 2..9 D0..7    (pull-up, 560 Ohm)
  4    SD    Brown   ----[===]---- 2..9 2..9 D0..7    (pull-up, 560 Ohm)
  START  (mainboard) -----|&gt;|----- 16   31   /INIT    (auto-reset, 1N4148)
  SELECT (mainboard) -----|&gt;|----- 16   31   /INIT    (auto-reset, 1N4148)
  RESET  (mainboard) -----||------ 16   31   /INIT    (auto-reset, 300nF)
</PRE></TD></TR></TBODY></TABLE>Notes: The GBA Pins are arranged from left to 
right as 2,4,6 in upper row, and 1,3,5 in lower row; outside view of GBA socket; 
flat side of socket upside. The above "Colors" are as used in most or all 
standard Nintendo link cables, note that Red/Orange will be exchanged at one end 
in cables with crossed SO/SI lines. At the PC side, use the SUBD pin numbers 
when connecting to a 25-pin SUBD plug, or CNTR pin numbers for 36-pin Centronics 
plug.<BR><BR><B>Optional SD Connection (Double Speed Burst)</B><BR>The SD line 
is used for Double Speed Burst transfers only, in case that you are using a 
gameboy link plug for the connection, and if that plug does not have a SD-pin 
(such like from older 8bit gameboy cables), then you may leave out this 
connection. Burst Boot will then only work half as fast 
though.<BR><BR><B>Optional Pull-Ups (Improves Low-to-High Transition 
Speed)</B><BR>If your parallel port works only with medium or slow delay 
settings, try to connect 560 Ohm resistors to SI/SC/SD inputs each, and the 
other resistor pin to any or all of the parallel port data lines (no$gba outputs 
high to pins 2..9).<BR><BR><B>Optional Reset Connection (CAUTION: Connection 
changed September 2004)</B><BR>The Reset connection allows to automatically 
reset &amp; upload data even if a program in the GBA has locked up (or if you've 
loaded a program that does not support nocash burst boot), without having to 
reset the GBA manually by switching it off and on (and without having to press 
Start+Select if a cartridge is inserted).<BR>The two diodes should be 1N4148 or 
similar, the capacitor should be 300nF (eg. three 100nF capacitors in parallel). 
The signals are labeled on the mainboard, and can be found at following names / 
CPU pin numbers: RESET/CPU.125, SELECT/TP2/CPU.126, 
START/TP3/CPU.127.<BR><BR><B>Optional Power Supply Connection</B><BR>Also, you 
may want to connect the power supply to parallel port data lines, see chapter 
Power Supply for details.<BR><BR><B>Transmission Speed</B><BR>The first transfer 
will be very slow, and the GBA BIOS will display the boot logo for at least 4 
seconds, even if the transfer has completed in less time. Once when you have 
uploaded a program with burst boot backdoor, further transfers will be ways 
faster. The table below shows transfer times for 0KByte - 256KByte files:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Boot Mode_____Delay 0_______Delay 1_______Delay 2_____
  Double Burst  0.1s - 1.8s   0.1s - 3.7s   0.1s - 5.3s
  Single Burst  0.1s - 3.6s   0.1s - 7.1s   0.1s - 10.6s
  Normal Bios   4.0s - 9.0s   4.0s - 12.7s  4.0s - 16.3s
</PRE></TD></TR></TBODY></TABLE>All timings measured on a 66MHz computer, best 
possible transmission speed should be 150KBytes/second. Timings might slightly 
vary depending on the CPU speed and/or operating system. Synchronization is done 
by I/O waitstates, that should work even on faster computers. Non-zero delays 
are eventually required for cables without 
pull-ups.<BR><BR><B>Requirements</B><BR>Beside for the cable and plugs, no 
special requirements.<BR>The cable should work with all parallel ports, 
including old-fashioned one-directional printer ports, as well as modern 
bi-directional EPP ports. Transfer timings should work stable regardless of the 
PCs CPU speed (see above though), and regardless of multitasking 
interruptions.<BR>Both no$gba and the actual transmission procedure are using 
some 32bit code, so that either one currently requires 80386SX CPUs or 
above.<BR><BR><B>Connection Examples</B><BR>As far as I can imagine, there are 
four possible methods how to connect the cable to the GBA. The first two methods 
don't require to open the GBA, and the other methods also allow to connect 
optional power supply and reset signal.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1) Connect it to the GBA link port. Advantage: No need to
     open/modify the GBA. Disadvantage: You need a special plug,
     (typically gained by removing it from a gameboy link cable).
  2) Solder the cable directly to the GBA link port pins. Advantages:
     No plug required &amp; no need to open the GBA. Disadvantages:
     You can't remove the cable, and the link port becomes unusable.
  3) Solder the cable directly to the GBA mainboard. Advantage: No
     plug required at the GBA side. Disadvantage: You'll always
     have a cable leaping out of the GBA even when not using it,
     unless you put a small standard plug between GBA and cable.
  4) Install a Centronics socket in the GBA (between power switch
     and headphone socket). Advantage: You can use a standard
     printer cable. Disadvantages: You need to cut a big hole into
     the GBAs battery box (which cannot be used anymore), the big
     cable might be a bit uncomfortable when holding the GBA.
</PRE></TD></TR></TBODY></TABLE>Personally, I've decided to use the lastmost 
method as I don't like ending up with hundreds of special cables for different 
purposes, and asides, it's been fun to damage the GAB as much as 
possible.<BR><BR><B>Note</B><BR>The above used PC parallel port signals are 
typically using 5V=HIGH while GBA link ports deal with 3V=HIGH. From my 
experiences, the different voltages do not cause communication problems (and do 
not damage the GBA and/or PC hardware), and after all real men don't care about 
a handful of volts, however, use at own risk.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxxbooflashcardupload></A><FONT size=+2>&nbsp;AUX Xboo 
      Flashcard Upload</FONT></TD></TR></TBODY></TABLE><BR><B>Flashcard 
Upload</B><BR>Allows to write data to flashcards which are plugged into GBA 
cartridge slot, cartridge is automatically started after writing. On initial 
power-up, hold down START+SELECT to prevent the GBA from booting the old program 
in the flashcard.<BR>The Upload function in Utility menu uses flashcard mode for 
files bigger than 256KB (otherwise uses multiboot mode automatically). Also, 
there's a separate Upload to Flashcard function in Remote Access submenu, 
allowing to write files of 256KB or less to flashcard if that should be 
desired.<BR><BR><B>Supported Flashcards</B><BR>Function currently tested with 
Visoly Flash Advance (FA) 256Mbit (32MB) Turbo cartridge. Should also work with 
older FA versions. Please let me know if you are using other flashcards which 
aren't yet supported.<BR><BR><B>Flashcard Performance</B><BR>Writing to 
flashcards may become potentially slow because of chip erase/write times, cable 
transmission time, and the sheer size of larger ROM-images. However, developers 
whom are testing different builts of their project usually won't need to rewrite 
the complete flashcard, Xboo uses a highspeed checksum mechanism (16MB/sec) to 
determine which flashcard sector(s) have changed, and does then re-write only 
these sector(s).<BR>To eliminate transmission time, data transfer takes place in 
the erase phases. Erase/write time depends on the flashcard type, should be 
circa 1-2 seconds per 256KB sector. Because the cartridge is programmed directly 
in the GBA there's no need to remove it from the GBA when writing to 
it.<BR><BR><B>Developers Advice</B><BR>Locate your program fragments at fixed 
addresses, for example, code and data blocks each aligned to 64K memory 
boundaries, so that data remains at the same location even when the size of code 
changes. Fill any blank spaces by value FFh for faster write time. Reduce the 
size of your ROM-image by efficient memory use (except for above alignment 
trick). Include the burst boot backdoor in your program, allowing to re-write 
the flashcard directly without resetting the GBA.<BR><BR><B>Lamers 
Advice</B><BR>Xboo Flashcard support does not mean to get lame &amp; to drop 
normal multiboot support, if your program fits into 256KB then make it 
&lt;both&gt; flashcard &lt;and&gt; multiboot compatible - multiboot reduces 
upload time, increases your flashcard lifetime, and will also work for people 
whom don't own flashcards.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=auxxbooburstbootbackdoor></A><FONT size=+2>&nbsp;AUX Xboo 
      Burst Boot Backdoor</FONT></TD></TR></TBODY></TABLE><BR>When writing Xboo 
compatible programs, always include a burst boot "backdoor", this will allow 
yourself (and other people) to upload programs much faster as when using the 
normal GBA BIOS multiboot function. Aside from the improved transmission speed, 
there's no need to reset the GBA each time (eventually manually if you do not 
have reset connect), without having to press Start+Select (if cartridge 
inserted), and, most important, the time-consuming nintendo-logo intro is 
bypassed.<BR><BR><B>The Burst Boot Protocol</B><BR>In your programs IRQ handler, 
add some code that watches out for burst boot IRQ requests. When sensing a burst 
boot request, download the actual boot procedure, and pass control to that 
procedure.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Send (PC)    Reply (GBA)
  "BRST"       "BOOT"        ;request burst, and reply &lt;prepared&gt; for boot
  &lt;wait 1/16s&gt; &lt;process IRQ&gt; ;long delay, allow slave to enter IRQ handler
  llllllll     "OKAY"        ;send length in bytes, reply &lt;ready&gt; to boot
  dddddddd     --------      ;send data in 32bit units, reply don't care
  cccccccc     cccccccc      ;exchange crc (all data units added together)
</PRE></TD></TR></TBODY></TABLE>Use normal mode, 32bit, external clock for all 
transfers. The received highspeed loader (currently approx. 180h bytes) is to be 
loaded to and started at 3000000h, which will then handle the actual download 
operation.<BR><BR>Below is an example program which works with multiboot, 
burstboot, and as normal rom/flashcard. The source can be assembled with a22i 
(the no$gba built-in assembler, see no$gba utility menu). When using 
other/mainstream assemblers, you'll eventually have to change some directives, 
convert numbers from NNNh into 0xNNN format, and define the origin somewhere in 
linker/makefile instead of in source code.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> .arm            ;select 32bit ARM instruction set
 .gba            ;indicate that it's a gameboy advance program
 .fix            ;automatically fix the cartridge header checksum
 org 2000000h    ;origin in RAM for multiboot-cable/no$gba-cutdown programs
 ;------------------
 ;cartridge header/multiboot header
  b     rom_start                ;-rom entry point
  dcb   ...insert logo here...   ;-nintento logo (156 bytes)
  dcb   'XBOO SAMPLE '           ;-title (12 bytes)
  dcb   0,0,0,0,  0,0            ;-game code (4 bytes), maker code (2 bytes)
  dcb   96h,0,0                  ;-fixed value 96h, main unit code, device type
  dcb   0,0,0,0,0,0,0            ;-reserved (7 bytes)
  dcb   0                        ;-software version number
  dcb   0                        ;-header checksum (set by .fix)
  dcb   0,0                      ;-reserved (2 bytes)
  b     ram_start                ;-multiboot ram entry point
  dcb   0,0                      ;-multiboot reserved bytes (destroyed by BIOS)
  dcb   0,0                      ;-blank padded (32bit alignment)
 ;------------------
 irq_handler:  ;interrupt handler (note: r0-r3 are pushed by BIOS)
  mov    r1,4000000h             ;\get I/O base address,
  ldr    r0,[r1,200h] ;IE/IF     ; read IE and IF,
  and    r0,r0,r0,lsr 16         ; isolate occurred AND enabled irqs,
  add    r3,r1,200h   ;IF        ; and acknowledge these in IF
  strh   r0,[r3,2]               ;/
  ldrh   r3,[r1,-8]              ;\mix up with BIOS irq flags at 3007FF8h,
  orr    r3,r3,r0                ; aka mirrored at 3FFFFF8h, this is required
  strh   r3,[r1,-8]              ;/when using the (VBlank-)IntrWait functions
  and    r3,r0,80h ;IE/IF.7 SIO  ;\
  cmp    r3,80h                  ; check if it's a burst boot interrupt
  ldreq  r2,[r1,120h] ;SIODATA32 ; (if interrupt caused by serial transfer,
  ldreq  r3,[msg_brst]           ; and if received data is "BRST",
  cmpeq  r2,r3                   ; then jump to burst boot)
  beq    burst_boot              ;/
  ;... insert your own interrupt handler code here ...
  bx     lr                      ;-return to the BIOS interrupt handler
 ;------------------
 burst_boot:     ;requires incoming r1=4000000h
  ;... if your program uses DMA, disable any active DMA transfers here ...
  ldr   r4,[msg_okay]            ;\
  bl    sio_transfer             ; receive transfer length/bytes &amp; reply "OKAY"
  mov   r2,r0 ;len               ;/
  mov   r3,3000000h   ;dst       ;\
  mov   r4,0  ;crc               ;
 @@lop:                          ;
  bl    sio_transfer             ; download burst loader to 3000000h and up
  stmia [r3]!,r0      ;dst       ;
  add   r4,r4,r0      ;crc       ;
  subs  r2,r2,4       ;len       ;
  bhi   @@lop                    ;/
  bl    sio_transfer             ;-send crc value to master
  b     3000000h  ;ARM state!    ;-launch actual transfer / start the loader
 ;------------------
 sio_transfer:  ;serial transfer subroutine, 32bit normal mode, external clock
  str   r4,[r1,120h]  ;siodata32 ;-set reply/send data
  ldr   r0,[r1,128h]  ;siocnt    ;\
  orr   r0,r0,80h                ; activate slave transfer
  str   r0,[r1,128h]  ;siocnt    ;/
 @@wait:                         ;\
  ldr   r0,[r1,128h]  ;siocnt    ; wait until transfer completed
  tst   r0,80h                   ;
  bne   @@wait                   ;/
  ldr   r0,[r1,120h]  ;siodata32 ;-get received data
  bx    lr
 ;---
 msg_boot dcb 'BOOT'     ;\
 msg_okay dcb "OKAY"     ; ID codes for the burstboot protocol
 msg_brst dcb "BRST"     ;/
 ;------------------
 download_rom_to_ram:
  mov  r0,8000000h  ;src/rom     ;\
  mov  r1,2000000h  ;dst/ram     ;
  mov  r2,40000h/16 ;length      ; transfer the ROM content
 @@lop:                          ; into RAM (done in units of 4 words/16 bytes)
  ldmia [r0]!,r4,r5,r6,r7        ; currently fills whole 256K of RAM,
  stmia [r1]!,r4,r5,r6,r7        ; even though the proggy is smaller
  subs  r2,r2,1                  ;
  bne   @@lop                    ;/
  sub   r15,lr,8000000h-2000000h ;-return (retadr rom/8000XXXh -&gt; ram/2000XXXh)
 ;------------------
 init_interrupts:
  mov  r4,4000000h               ;-base address for below I/O registers
  ldr  r0,=irq_handler           ;\install IRQ handler address
  str  r0,[r4,-4]   ;IRQ HANDLER ;/at 3FFFFFC aka 3007FFC
  mov  r0,0008h                  ;\enable generating vblank irqs
  strh r0,[r4,4h]   ;DISPSTAT    ;/
  mrs  r0,cpsr                   ;\
  bic  r0,r0,80h                 ; cpu interrupt enable (clear i-flag)
  msr  cpsr,r0                   ;/
  mov  r0,0                      ;\
  str  r0,[r4,134h] ;RCNT        ; init SIO normal mode, external clock,
  ldr  r0,=5080h                 ; 32bit, IRQ enable, transfer started
  str  r0,[r4,128h] ;SIOCNT      ; output "BOOT" (indicate burst boot prepared)
  ldr  r0,[msg_boot]             ;
  str  r0,[r4,120h] ;SIODATA32   ;/
  mov  r0,1                      ;\interrupt master enable
  str  r0,[r4,208h] ;IME=1       ;/
  mov  r0,81h                    ;\enable execution of vblank IRQs,
  str  r0,[r4,200h] ;IE=81h      ;/and of SIO IRQs (burst boot)
  bx   lr
 ;------------------
 rom_start:   ;entry point when booted from flashcart/rom
  bl   download_rom_to_ram       ;-download ROM to RAM (returns to ram_start)
 ram_start:   ;entry point for multiboot/burstboot
  mov  r0,0feh                   ;\reset all registers, and clear all memory
  swi  10000h ;RegisterRamReset  ;/(except program code in wram at 2000000h)
  bl   init_interrupts           ;-install burst boot irq handler
  mov  r4,4000000h               ;\enable video,
  strh r4,[r4,000h] ;DISPCNT     ;/by clearing the forced blank bit
 @@mainloop:
  swi  50000h ;VBlankIntrWait    ;-wait one frame (cpu in low power mode)
  mov  r5,5000000h               ;\increment the backdrop palette color
  str  r8,[r5]                   ; (ie. display a blinking screen)
  add  r8,r8,1                   ;/
  b    @@mainloop
 ;------------------
 .pool
 end
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpureference></A><FONT size=+2>&nbsp;CPU 
  Reference</FONT></TD></TR></TBODY></TABLE><BR><B>General ARM7TDMI 
Information</B><BR><A href="http://nocash.emubase.de/gbatek.htm#cpuoverview">CPU 
Overview</A><BR><A href="http://nocash.emubase.de/gbatek.htm#cpuregisterset">CPU 
Register Set</A><BR><A href="http://nocash.emubase.de/gbatek.htm#cpuflags">CPU 
Flags</A><BR><A href="http://nocash.emubase.de/gbatek.htm#cpuexceptions">CPU 
Exceptions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#cpumemoryalignments">CPU Memory 
Alignments</A><BR><BR><B>The ARM7TDMI Instruction Sets</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumbinstructionset">THUMB Instruction 
Set</A><BR><A href="http://nocash.emubase.de/gbatek.htm#arminstructionset">ARM 
Instruction Set</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#pseudoinstructionsanddirectives">Pseudo 
Instructions and Directives</A><BR><BR><B>Further Information</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#cpuinstructioncycletimes">CPU 
Instruction Cycle Times</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#cpuversions">CPU Versions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#cpudatasheet">CPU Data 
Sheet</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuoverview></A><FONT size=+2>&nbsp;CPU 
  Overview</FONT></TD></TR></TBODY></TABLE><BR>The ARM7TDMI is a 32bit RISC 
(Reduced Instruction Set Computer) CPU, designed by ARM (Advanced RISC 
Machines), and designed for both high performance and low power 
consumption.<BR><BR><B>Fast Execution</B><BR>Depending on the CPU state, all 
opcodes are sized 32bit or 16bit (that's counting both the opcode bits and its 
parameters bits) providing fast decoding and execution. Additionally, pipelining 
allows - (a) one instruction to be executed while (b) the next instruction is 
decoded and (c) the next instruction is fetched from memory - all at the same 
time.<BR><BR><B>Data Formats</B><BR>The CPU manages to deal with 8bit, 16bit, 
and 32bit data, that are called:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>   8bit - Byte
  16bit - Halfword
  32bit - Word
</PRE></TD></TR></TBODY></TABLE><BR><B>The two CPU states</B><BR>As mentioned 
above, two CPU states exist:<BR>- ARM state: Uses the full 32bit instruction set 
(32bit opcodes)<BR>- THUMB state: Uses a cutdown 16bit instruction set (16bit 
opcodes)<BR>Regardless of the opcode-width, both states are using 32bit 
registers, allowing 32bit memory addressing as well as 32bit arithmetic/logical 
operations.<BR><BR><B>When to use ARM state</B><BR>Basically, there are two 
advantages in ARM state:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> - Each single opcode provides more functionality, resulting
   in faster execution when using a 32bit bus memory system
   (such like opcodes stored in GBA Work RAM).
 - All registers R0-R15 can be accessed directly.
</PRE></TD></TR></TBODY></TABLE>The downsides are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> - Not so fast when using 16bit memory system
   (but it still works though).
 - Program code occupies more memory space.
</PRE></TD></TR></TBODY></TABLE><BR><B>When to use THUMB state</B><BR>There are 
two major advantages in THUMB state:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> - Faster execution up to approx 160% when using a 16bit bus
   memory system (such like opcodes stored in GBA GamePak ROM).
 - Reduces code size, decreases memory overload down to approx 65%.
</PRE></TD></TR></TBODY></TABLE>The disadvantages are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> - Not as multi-functional opcodes as in ARM state, so it will
   be sometimes required use more than one opcode to gain a
   similar result as for a single opcode in ARM state.
 - Most opcodes allow only registers R0-R7 to be used directly.
</PRE></TD></TR></TBODY></TABLE><BR><B>Combining ARM and THUMB 
state</B><BR>Switching between ARM and THUMB state is done by a normal branch 
(BX) instruction which takes only a handful of cycles to execute (allowing to 
change states as often as desired - with almost no overload).<BR><BR>Also, as 
both ARM and THUMB are using the same register set, it is possible to pass data 
between ARM and THUMB mode very easily.<BR><BR>The best memory &amp; execution 
performance can be gained by combining both states: THUMB for normal program 
code, and ARM code for timing critical subroutines (such like interrupt 
handlers, or complicated algorithms).<BR><BR>Note: ARM and THUMB code cannot be 
executed simultaneously.<BR><BR><B>Automatic state changes</B><BR>Beside for the 
above manual state switching by using BX instructions, the following situations 
involve automatic state changes:<BR>- CPU switches to ARM state when executing 
an exception<BR>- User switches back to old state when leaving an 
exception<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuregisterset></A><FONT size=+2>&nbsp;CPU Register 
    Set</FONT></TD></TR></TBODY></TABLE><BR><B>Overview</B><BR>The following table 
shows the ARM7TDMI register set which is available in each mode. There's a total 
of 37 registers (32bit each), 31 general registers (Rxx) and 6 status registers 
(xPSR).<BR>Note that only some registers are 'banked', for example, each mode 
has it's own R14 register: called R14, R14_fiq, R14_svc, etc. for each mode 
respectively.<BR>However, other registers are not banked, for example, each mode 
is using the same R0 register, so writing to R0 will always affect the content 
of R0 in other modes also.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  System/User FIQ       Supervisor Abort     IRQ       Undefined</B>
  --------------------------------------------------------------
  R0          R0        R0         R0        R0        R0
  R1          R1        R1         R1        R1        R1
  R2          R2        R2         R2        R2        R2
  R3          R3        R3         R3        R3        R3
  R4          R4        R4         R4        R4        R4
  R5          R5        R5         R5        R5        R5
  R6          R6        R6         R6        R6        R6
  R7          R7        R7         R7        R7        R7
  --------------------------------------------------------------
  R8          R8_fiq    R8         R8        R8        R8
  R9          R9_fiq    R9         R9        R9        R9
  R10         R10_fiq   R10        R10       R10       R10
  R11         R11_fiq   R11        R11       R11       R11
  R12         R12_fiq   R12        R12       R12       R12
  R13 (SP)    R13_fiq   R13_svc    R13_abt   R13_irq   R13_und
  R14 (LR)    R14_fiq   R14_svc    R14_abt   R14_irq   R14_und
  R15 (PC)    R15       R15        R15       R15       R15
  --------------------------------------------------------------
  CPSR        CPSR      CPSR       CPSR      CPSR      CPSR
  --          SPSR_fiq  SPSR_svc   SPSR_abt  SPSR_irq  SPSR_und
  --------------------------------------------------------------
</PRE></TD></TR></TBODY></TABLE><BR><B>R0-R12 Registers (General Purpose 
Registers)</B><BR>These thirteen registers may be used for whatever general 
purposes. Basically, each is having same functionality and performance, ie. 
there is no 'fast accumulator' for arithmetic operations, and no 'special 
pointer register' for memory addressing.<BR>However, in THUMB mode only R0-R7 
(Lo registers) may be accessed freely, while R8-R12 and up (Hi registers) can be 
accessed only by some instructions.<BR><BR><B>R13 Register (SP)</B><BR>This 
register is used as Stack Pointer (SP) in THUMB state. While in ARM state the 
user may decided to use R13 and/or other register(s) as stack pointer(s), or as 
general purpose register.<BR>As shown in the table above, there's a separate R13 
register in each mode, and (when used as SP) each exception handler may (and 
MUST!) use its own stack.<BR><BR><B>R14 Register (LR)</B><BR>This register is 
used as Link Register (LR). That is, when calling to a sub-routine by a Branch 
with Link (BL) instruction, then the return address (ie. old value of PC) is 
saved in this register.<BR>Storing the return address in the LR register is 
obviously faster than pushing it into memory, however, as there's only one LR 
register for each mode, the user must manually push its content before issuing 
'nested' subroutines.<BR>Same happens when an exception is called, PC is saved 
in LR of new mode.<BR>Note: In ARM mode, R14 may be used as general purpose 
register also, provided that above usage as LR register isn't 
required.<BR><BR><B>R15 Register (PC)</B><BR>R15 is always used as program 
counter (PC). Note that when reading R15, this will usually return a value of 
PC+nn because of read-ahead (pipelining), whereas 'nn' depends on the 
instruction and on the CPU state (ARM or THUMB).<BR><BR><B>CPSR and SPSR 
(Program Status Registers) (ARMv3 and up)</B><BR>The current condition codes 
(flags) and CPU control bits are stored in the CPSR register. When an exception 
arises, the old CPSR is saved in the SPSR of the respective exception-mode (much 
like PC is saved in LR).<BR>For details refer to chapter about CPU 
Flags.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuflags></A><FONT size=+2>&nbsp;CPU 
Flags</FONT></TD></TR></TBODY></TABLE><BR><B>Current Program Status Register 
(CPSR)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  31    N - Sign Flag       (0=Not Signed, 1=Signed)
  30    Z - Zero Flag       (0=Not Zero, 1=Zero)
  29    C - Carry Flag      (0=No Carry, 1=Carry)
  28    V - Overflow Flag   (0=No Overflow, 1=Overflow)
  27    Q - Sticky Overflow (1=Sticky Overflow, ARMv5TE and up only)
  26-8  Reserved            (For future use) - Do not change manually!
  7     I - IRQ disable     (0=Enable, 1=Disable)
  6     F - FIQ disable     (0=Enable, 1=Disable)
  5     T - State Bit       (0=ARM, 1=THUMB) - Do not change manually!
  4-0   M4-M0 - Mode Bits   (See below)
</PRE></TD></TR></TBODY></TABLE><BR><B>Bit 31-28: Condition Code Flags 
(N,Z,C,V)</B><BR>These bits reflect results of logical or arithmetic 
instructions. In ARM mode, it is often optionally whether an instruction should 
modify flags or not, for example, it is possible to execute a SUB instruction 
that does NOT modify the condition flags.<BR>In ARM state, all instructions can 
be executed conditionally depending on the settings of the flags, such like 
MOVEQ (Move if Z=1). While In THUMB state, only Branch instructions (jumps) can 
be made conditionally.<BR><BR><B>Bit 27: Sticky Overflow Flag (Q) - ARMv5TE and 
ARMv5TExP and up only</B><BR>Used by QADD, QSUB, QDADD, QDSUB, SMLAxy, and 
SMLAWy only. These opcodes set the Q-flag in case of overflows, but leave it 
unchanged otherwise. The Q-flag can be tested/reset by MSR/MRS opcodes 
only.<BR><BR><B>Bit 27-8: Reserved Bits (except Bit 27 on ARMv5TE and up, see 
above)</B><BR>These bits are reserved for possible future implementations. For 
best forwards compatibility, the user should never change the state of these 
bits, and should not expect these bits to be set to a specific 
value.<BR><BR><B>Bit 7-0: Control Bits (I,F,T,M4-M0)</B><BR>These bits may 
change when an exception occurs. In privileged modes (non-user modes) they may 
be also changed manually.<BR>The interrupt bits I and F are used to disable IRQ 
and FIQ interrupts respectively (a setting of "1" means disabled).<BR>The T Bit 
signalizes the current state of the CPU (0=ARM, 1=THUMB), this bit should never 
be changed manually - instead, changing between ARM and THUMB state must be done 
by BX instructions.<BR>The Mode Bits M4-M0 contain the current operating 
mode.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Binary Hex Dec  Expl.
  10000b 10h 16 - User (non-privileged)
  10001b 11h 17 - FIQ
  10010b 12h 18 - IRQ
  10011b 13h 19 - Supervisor (SWI)
  10111b 17h 23 - Abort
  11011b 1Bh 27 - Undefined
  11111b 1Fh 31 - System (privileged 'User' mode) (ARMv4 and up)
</PRE></TD></TR></TBODY></TABLE>Writing any other values into the Mode bits is 
not allowed.<BR><BR><B>Saved Program Status Registers 
(SPSR_&lt;mode&gt;)</B><BR>Additionally to above CPSR, five Saved Program Status 
Registers exist:<BR>SPSR_fiq, SPSR_svc, SPSR_abt, SPSR_irq, SPSR_und<BR>Whenever 
the CPU enters an exception, the current status register (CPSR) is copied to the 
respective SPSR_&lt;mode&gt; register. Note that there is only one SPSR for each 
mode, so nested exceptions inside of the same mode are allowed only if the 
exception handler saves the content of SPSR in memory.<BR>For example, for an 
IRQ exception: IRQ-mode is entered, and CPSR is copied to SPSR_irq. If the 
interrupt handler wants to enable nested IRQs, then it must first push SPSR_irq 
before doing so.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuexceptions></A><FONT size=+2>&nbsp;CPU 
  Exceptions</FONT></TD></TR></TBODY></TABLE><BR>Exceptions are caused by 
interrupts or errors. In the ARM7TDMI the following exceptions may arise, sorted 
by priority, starting with highest priority:<BR>- Reset<BR>- Data Abort<BR>- 
FIQ<BR>- IRQ<BR>- Prefetch Abort<BR>- Software Interrupt<BR>- Undefined 
Instruction<BR><BR><B>Exception Vectors</B><BR>The following are the exception 
vectors in memory. That is, when an exception arises, CPU is switched into ARM 
state, and the program counter (PC) is loaded by the respective address.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Address    Exception                  Mode on Entry      Interrupt Flags
  BASE+00h   Reset                      Supervisor (_svc)  I=1, F=1
  BASE+04h   Undefined Instruction      Undefined  (_und)  I=1, F=unchanged
  BASE+08h   Software Interrupt (SWI)   Supervisor (_svc)  I=1, F=unchanged
  BASE+0Ch   Prefetch Abort             Abort      (_abt)  I=1, F=unchanged
  BASE+10h   Data Abort                 Abort      (_abt)  I=1, F=unchanged
  BASE+14h   (Reserved)                 -          -       -
  BASE+18h   Normal Interrupt (IRQ)     IRQ        (_irq)  I=1, F=unchanged
  BASE+1Ch   Fast Interrupt (FIQ)       FIQ        (_fiq)  I=1, F=1
</PRE></TD></TR></TBODY></TABLE>BASE is normally 00000000h, but may be 
optionally FFFF0000h in some ARM CPUs.<BR>As there's only space for one ARM 
opcode at each of the above addresses, it'd be usually recommended to deposit a 
Branch opcode into each vector, which'd then redirect to the actual exception 
handlers address.<BR><BR><B>Actions performed by CPU when entering an 
exception</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  - R14=PC+nn              ;save old PC, ie. return address
  - SPSR_&lt;new mode&gt;=CPSR   ;save old flags
  - CPSR new T,M bits      ;set to T=0 (ARM state), and M4-0=new mode
  - CPSR new I bit         ;IRQs disabled (I=1), done by ALL exceptions
  - CPSR new F bit         ;FIQs disabled (F=1), done by Reset and FIQ only
  - PC=exception_vector    ;see table above
</PRE></TD></TR></TBODY></TABLE>Above "PC+nn" depends on the type of exception. 
Basically, in ARM state that nn-offset is caused by pipelining, and in THUMB 
state an identical ARM-style 'offset' is generated (even though the 'base 
address' may be only halfword-aligned).<BR><BR><B>Required user-handler actions 
when returning from an exception</B><BR>Restore any general registers (R0-R14) 
which might have been modified by the exception handler. Use return-instruction 
as listed in the respective descriptions below, this will both restore PC and 
CPSR - that automatically involves that the old CPU state (THUMB or ARM) as well 
as old state of FIQ and IRQ disable flags are restored.<BR>As mentioned above 
(see action on entering...), the return address is always saved in ARM-style 
format, so that exception handler may use the same return-instruction, 
regardless of whether the exception has been generated from inside of ARM or 
THUMB state.<BR><BR><B>FIQ (Fast Interrupt Request)</B><BR>This interrupt is 
generated by a LOW level on the nFIQ input. It is supposed to process timing 
critical interrupts at a high priority, as fast as possible.<BR>Additionally to 
the common banked registers (R13_fiq,R14_fiq), five extra banked registers 
(R8_fiq-R12_fiq) are available in FIQ mode. The exception handler may freely 
access these registers without modifying the main programs R8-R12 registers (and 
without having to save that registers on stack).<BR>In privileged (non-user) 
modes, FIQs may be also manually disabled by setting the F Bit in 
CPSR.<BR><BR><B>IRQ (Normal Interrupt Request)</B><BR>This interrupt is 
generated by a LOW level on the nIRQ input. Unlike FIQ, the IRQ mode is not 
having its own banked R8-R12 registers.<BR>IRQ is having lower priority than 
FIQ, and IRQs are automatically disabled when a FIQ exception becomes executed. 
In privileged (non-user) modes, IRQs may be also manually disabled by setting 
the I Bit in CPSR.<BR>To return from IRQ Mode (continuing at following 
opcode):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  SUBS PC,R14,4   ;both PC=R14_irq-4, and CPSR=SPSR_irq
</PRE></TD></TR></TBODY></TABLE><BR><B>Software Interrupt</B><BR>Generated by a 
software interrupt instruction (SWI). Recommended to request a supervisor 
(operating system) function. The SWI instruction may also contain a parameter in 
the 'comment field' of the opcode:<BR>In case that your main program issues SWIs 
from both inside of THUMB and ARM states, then your exception handler must 
separate between 24bit comment fields in ARM opcodes, and 8bit comment fields in 
THUMB opcodes (if necessary determine old state by examining T Bit in SPSR_svc); 
However, in Little Endian mode, you could use only the most significant 8bits of 
the 24bit ARM comment field (as done in the GBA, for example) - the exception 
handler could then process the BYTE at [R14-2], regardless of whether it's been 
called from ARM or THUMB state.<BR>To return from Supervisor Mode (continuing at 
following opcode):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MOVS PC,R14   ;both PC=R14_svc, and CPSR=SPSR_svc
</PRE></TD></TR></TBODY></TABLE>Note: Like all other exceptions, SWIs are always 
executed in ARM state, no matter whether it's been caused by an ARM or THUMB 
state SWI instruction.<BR><BR><B>Undefined Instruction Exception (supported by 
ARMv3 and up)</B><BR>This exception is generated when the CPU comes across an 
instruction which it cannot handle. Most likely signalizing that the program has 
locked up, and that an errormessage should be displayed.<BR>However, it might be 
also used to emulate custom functions, ie. as an additional 'SWI' instruction 
(which'd use R14_und and SPSR_und though, and it'd thus allow to execute the 
Undefined Instruction handler from inside of Supervisor mode without having to 
save R14_svc and SPSR_svc).<BR>To return from Undefined Mode (continuing at 
following opcode):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MOVS PC,R14   ;both PC=R14_und, and CPSR=SPSR_und
</PRE></TD></TR></TBODY></TABLE>Note that not all unused opcodes are necessarily 
producing an exception, for example, an ARM state Multiply instruction with Bit 
6 set to "1" would be blindly accepted as 'legal' opcode.<BR><BR><B>Abort 
(supported by ARMv3 and up)</B><BR>Aborts (page faults) are mostly supposed for 
virtual memory systems (ie. not used in GBA, as far as I know), otherwise they 
might be used just to display an error message. Two types of aborts exists:<BR>- 
Prefetch Abort (occurs during an instruction prefetch)<BR>- Prefetch Abort (also 
occurs on BKPT opcodes, ARMv5 and up)<BR>- Data Abort (occurs during a data 
access)<BR>A virtual memory systems abort handler would then most likely 
determine the fault address: For prefetch abort that's just "R14_abt-4". For 
Data abort, the THUMB or ARM instruction at "R14_abt-8" needs to be 
'disassembled' in order to determine the addressed data in memory.<BR>The 
handler would then fix the error by loading the respective memory page into 
physical memory, and then retry to execute the SAME instruction again, by 
returning as follows:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  prefetch abort: SUBS PC,R14,#4   ;PC=R14_abt-4, and CPSR=SPSR_abt
  data abort:     SUBS PC,R14,#8   ;PC=R14_abt-8, and CPSR=SPSR_abt
</PRE></TD></TR></TBODY></TABLE>Separate exception vectors for prefetch/data 
abort exists, each should use the respective return instruction as shown 
above.<BR><BR><B>Reset</B><BR>Forces PC=VVVV0000h, and forces control bits of 
CPSR to T=0 (ARM state), F=1 and I=1 (disable FIQ and IRQ), and M4-0=10011b 
(Supervisor mode).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpumemoryalignments></A><FONT size=+2>&nbsp;CPU Memory 
      Alignments</FONT></TD></TR></TBODY></TABLE><BR>The CPU does NOT support 
accessing mis-aligned addresses (which would be rather slow because it'd have to 
merge/split that data into two accesses).<BR>When reading/writing code/data 
to/from memory, Words and Halfwords must be located at well-aligned memory 
address, ie. 32bit words aligned by 4, and 16bit halfwords aligned by 
2.<BR><BR><B>Mis-aligned STR,STRH,STM,LDM,LDRD,STRD,PUSH,POP (forced 
align)</B><BR>The mis-aligned low bit(s) are ignored, the memory access goes to 
a forcibly aligned (rounded-down) memory address.<BR>For LDRD/STRD, it isn't 
clearly defined if the address must be aligned by 8 (on the NDS, align-4 seems 
to be okay) (align-8 may be required on other CPUs with 64bit 
databus).<BR><BR><B>Mis-aligned LDR,SWP (rotated read)</B><BR>Reads from 
forcibly aligned address "addr AND (NOT 3)", and does then rotate the data as 
"ROR (addr AND 3)*8". That effect is internally used by LDRB and LDRH opcodes 
(which do then mask-out the unused bits).<BR>The SWP opcode works like a 
combination of LDR and STR, that means, it does read-rotated, but does 
write-unrotated.<BR><BR><B>Mis-aligned LDRH,LDRSH (does or does not do strange 
things)</B><BR>On ARM9 aka ARMv5 aka NDS9:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LDRH Rd,[odd]   --&gt;  LDRH Rd,[odd-1]        ;forced align
  LDRSH Rd,[odd]  --&gt;  LDRSH Rd,[odd-1]       ;forced align
</PRE></TD></TR></TBODY></TABLE>On ARM7 aka ARMv5 aka NDS7/GBA:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LDRH Rd,[odd]   --&gt;  LDRH Rd,[odd-1] ROR 8  ;read to bit0-7 and bit24-31
  LDRSH Rd,[odd]  --&gt;  LDRSB Rd,[odd]         ;sign-expand BYTE value
</PRE></TD></TR></TBODY></TABLE><BR><B>Mis-aligned PC/R15 (branch opcodes, or 
MOV/ALU/LDR with Rd=R15)</B><BR>For ARM code, the low bits of the target address 
should be usually zero, otherwise, R15 is forcibly aligned by clearing the lower 
two bits.<BR>For THUMB code, the low bit of the target address may/should/must 
be set, the bit is (or is not) interpreted as thumb-bit (depending on the 
opcode), and R15 is then forcibly aligned by clearing the lower bit.<BR>In 
short, R15 will be always forcibly aligned, so mis-aligned branches won't have 
effect on subsequent opcodes that use R15, or [R15+disp] as operand.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumbinstructionset></A><FONT size=+2>&nbsp;THUMB Instruction 
      Set</FONT></TD></TR></TBODY></TABLE><BR>When operating in THUMB state, cut-down 
16bit opcodes are used.<BR>THUMB supported on T-variants of ARMv4 and up, ie. 
ARMv4T, ARMv5T, etc.<BR><BR><B>Summary</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumbinstructionsummary">THUMB 
Instruction Summary</A><BR><BR><B>Register Operations</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb1moveshiftedregister">THUMB.1: 
move shifted register</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb2addsubtract">THUMB.2: 
add/subtract</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb3movecompareaddsubtractimmediate">THUMB.3: 
move/compare/add/subtract immediate</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb4aluoperations">THUMB.4: ALU 
operations</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb5hiregisteroperationsbranchexchange">THUMB.5: 
Hi register operations/branch exchange</A><BR><BR><B>Memory Addressing 
Operations</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb6loadpcrelative">THUMB.6: load 
PC-relative</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb7loadstorewithregisteroffset">THUMB.7: 
load/store with register offset</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb8loadstoresignextendedbytehalfword">THUMB.8: 
load/store sign-extended byte/halfword</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb9loadstorewithimmediateoffset">THUMB.9: 
load/store with immediate offset</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb10loadstorehalfword">THUMB.10: 
load/store halfword</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb11loadstoresprelative">THUMB.11: 
load/store SP-relative</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb12getrelativeaddress">THUMB.12: 
get relative address</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb13addoffsettostackpointer">THUMB.13: 
add offset to stack pointer</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb14pushpopregisters">THUMB.14: 
push/pop registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb15multipleloadstore">THUMB.15: 
multiple load/store</A><BR><BR><B>Jumps and Calls</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb16conditionalbranch">THUMB.16: 
conditional branch</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb17softwareinterruptandbreakpoint">THUMB.17: 
software interrupt and breakpoint</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb18unconditionalbranch">THUMB.18: 
unconditional branch</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#thumb19longbranchwithlink">THUMB.19: 
long branch with link</A><BR>(See also THUMB.5: BX Rs, and ADD/MOV 
PC,Rs.)<BR><BR><B>Note:</B><BR>Switching between ARM and THUMB state can be done 
by using the Branch and Exchange (BX) instruction.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumbinstructionsummary></A><FONT size=+2>&nbsp;THUMB 
      Instruction Summary</FONT></TD></TR></TBODY></TABLE><BR>The table below lists 
all THUMB mode instructions with clock cycles, affected CPSR flags, 
Format/chapter number, and description.<BR>Only register R0..R7 can be used in 
thumb mode (unless R8-15,SP,PC are explicitly mentioned).<BR><BR><B>Logical 
Operations</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction        Cycles Flags Format Expl.
  MOV Rd,Imm8bit      1S     NZ--  3   Rd=nn
  MOV Rd,Rs           1S     NZ00  2   Rd=Rs+0
  MOV R0..14,R8..15   1S     ----  5   Rd=Rs
  MOV R8..14,R0..15   1S     ----  5   Rd=Rs
  MOV R15,R0..15      2S+1N  ----  5   PC=Rs
  MVN Rd,Rs           1S     NZ--  4   Rd=NOT Rs
  AND Rd,Rs           1S     NZ--  4   Rd=Rd AND Rs
  TST Rd,Rs           1S     NZ--  4 Void=Rd AND Rs
  BIC Rd,Rs           1S     NZ--  4   Rd=Rd AND NOT Rs
  ORR Rd,Rs           1S     NZ--  4   Rd=Rd OR Rs
  EOR Rd,Rs           1S     NZ--  4   Rd=Rd XOR Rs
  LSL Rd,Rs,Imm5bit   1S     NZc-  1   Rd=Rs SHL nn
  LSL Rd,Rs           1S+1I  NZc-  4   Rd=Rd SHL (Rs AND 0FFh)
  LSR Rd,Rs,Imm5bit   1S     NZc-  1   Rd=Rs SHR nn
  LSR Rd,Rs           1S+1I  NZc-  4   Rd=Rd SHR (Rs AND 0FFh)
  ASR Rd,Rs,Imm5bit   1S     NZc-  1   Rd=Rs SAR nn
  ASR Rd,Rs           1S+1I  NZc-  4   Rd=Rd SAR (Rs AND 0FFh)
  ROR Rd,Rs           1S+1I  NZc-  4   Rd=Rd ROR (Rs AND 0FFh)
  NOP                 1S     ----  5   R8=R8
</PRE></TD></TR></TBODY></TABLE>Carry flag affected only if shift amount is 
non-zero.<BR><BR><B>Arithmetic Operations and Multiply</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction        Cycles Flags Format Expl.
  ADD Rd,Rs,Imm3bit   1S     NZCV  2   Rd=Rs+nn
  ADD Rd,Imm8bit      1S     NZCV  3   Rd=Rd+nn
  ADD Rd,Rs,Rn        1S     NZCV  2   Rd=Rs+Rn
  ADD R0..14,R8..15   1S     ----  5   Rd=Rd+Rs
  ADD R8..14,R0..15   1S     ----  5   Rd=Rd+Rs
  ADD R15,R0..15      2S+1N  ----  5   PC=Rd+Rs
  ADD Rd,PC,Imm8bit*4 1S     ---- 12   Rd=(($+4) AND NOT 2)+nn
  ADD Rd,SP,Imm8bit*4 1S     ---- 12   Rd=SP+nn
  ADD SP,Imm7bit*4    1S     ---- 13   SP=SP+nn
  ADD SP,-Imm7bit*4   1S     ---- 13   SP=SP-nn
  ADC Rd,Rs           1S     NZCV  4   Rd=Rd+Rs+Cy
  SUB Rd,Rs,Imm3Bit   1S     NZCV  2   Rd=Rs-nn
  SUB Rd,Imm8bit      1S     NZCV  3   Rd=Rd-nn
  SUB Rd,Rs,Rn        1S     NZCV  2   Rd=Rs-Rn
  SBC Rd,Rs           1S     NZCV  4   Rd=Rd-Rs-NOT Cy
  NEG Rd,Rs           1S     NZCV  4   Rd=0-Rs
  CMP Rd,Imm8bit      1S     NZCV  3 Void=Rd-nn
  CMP Rd,Rs           1S     NZCV  4 Void=Rd-Rs
  CMP R0-15,R8-15     1S     NZCV  5 Void=Rd-Rs
  CMP R8-15,R0-15     1S     NZCV  5 Void=Rd-Rs
  CMN Rd,Rs           1S     NZCV  4 Void=Rd+Rs
  MUL Rd,Rs           1S+mI  NZx-  4   Rd=Rd*Rs
</PRE></TD></TR></TBODY></TABLE><BR><B>Jumps and Calls</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction        Cycles    Flags Format Expl.
  B disp              2S+1N     ---- 18  PC=$+/-2048
  BL disp             3S+1N     ---- 19  PC=$+/-4M, LR=$+5
  B{cond=true} disp   2S+1N     ---- 16  PC=$+/-0..256
  B{cond=false} disp  1S        ---- 16  N/A
  BX R0..15           2S+1N     ----  5  PC=Rs, ARM/THUMB (Rs bit0)
  SWI Imm8bit         2S+1N     ---- 17  PC=8, ARM SVC mode, LR=$+2
  BKPT Imm8bit        ???       ---- 17  ??? ARM9 Prefetch Abort
  BLX disp            ???       ---- ??? ??? ARM9
  BLX R0..R14         ???       ---- ??? ??? ARM9
  POP {Rlist,}PC   (n+1)S+2N+1I ---- 14
  MOV R15,R0..15      2S+1N     ----  5  PC=Rs
  ADD R15,R0..15      2S+1N     ----  5  PC=Rd+Rs
</PRE></TD></TR></TBODY></TABLE>The thumb BL instruction occupies two 16bit 
opcodes, 32bit in total.<BR><BR><B>Memory Load/Store</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction        Cycles    Flags Format Expl.
  LDR  Rd,[Rb,5bit*4] 1S+1N+1I  ----  9  Rd = WORD[Rb+nn]
  LDR  Rd,[PC,8bit*4] 1S+1N+1I  ----  6  Rd = WORD[PC+nn]
  LDR  Rd,[SP,8bit*4] 1S+1N+1I  ---- 11  Rd = WORD[SP+nn]
  LDR  Rd,[Rb,Ro]     1S+1N+1I  ----  7  Rd = WORD[Rb+Ro]
  LDRB Rd,[Rb,5bit*1] 1S+1N+1I  ----  9  Rd = BYTE[Rb+nn]
  LDRB Rd,[Rb,Ro]     1S+1N+1I  ----  7  Rd = BYTE[Rb+Ro]
  LDRH Rd,[Rb,5bit*2] 1S+1N+1I  ---- 10  Rd = HALFWORD[Rb+nn]
  LDRH Rd,[Rb,Ro]     1S+1N+1I  ----  8  Rd = HALFWORD[Rb+Ro]
  LDSB Rd,[Rb,Ro]     1S+1N+1I  ----  8  Rd = SIGNED_BYTE[Rb+Ro]
  LDSH Rd,[Rb,Ro]     1S+1N+1I  ----  8  Rd = SIGNED_HALFWORD[Rb+Ro]
  STR  Rd,[Rb,5bit*4] 2N        ----  9  WORD[Rb+nn] = Rd
  STR  Rd,[SP,8bit*4] 2N        ---- 11  WORD[SP+nn] = Rd
  STR  Rd,[Rb,Ro]     2N        ----  7  WORD[Rb+Ro] = Rd
  STRB Rd,[Rb,5bit*1] 2N        ----  9  BYTE[Rb+nn] = Rd
  STRB Rd,[Rb,Ro]     2N        ----  7  BYTE[Rb+Ro] = Rd
  STRH Rd,[Rb,5bit*2] 2N        ---- 10  HALFWORD[Rb+nn] = Rd
  STRH Rd,[Rb,Ro]     2N        ----  8  HALFWORD[Rb+Ro]=Rd
  PUSH {Rlist}{LR}    (n-1)S+2N ---- 14
  POP  {Rlist}{PC}              ---- 14  (ARM9: with mode switch)
  STMIA Rb!,{Rlist}   (n-1)S+2N ---- 15
  LDMIA Rb!,{Rlist}   nS+1N+1I  ---- 15
</PRE></TD></TR></TBODY></TABLE><BR><B>THUMB Binary Opcode Format</B><BR>This 
table summarizes the position of opcode/parameter bits for THUMB mode 
instructions, Format 1-19.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Form|_15|_14|_13|_12|_11|_10|_9_|_8_|_7_|_6_|_5_|_4_|_3_|_2_|_1_|_0_|
 __1_|_0___0___0_|__Op___|_______Offset______|____Rs_____|____Rd_____|Shifted
 __2_|_0___0___0___1___1_|_I,_Op_|___Rn/nn___|____Rs_____|____Rd_____|ADD/SUB
 __3_|_0___0___1_|__Op___|____Rd_____|_____________Offset____________|Immedi.
 __4_|_0___1___0___0___0___0_|______Op_______|____Rs_____|____Rd_____|AluOp
 __5_|_0___1___0___0___0___1_|__Op___|Hd_|Hs_|____Rs_____|____Rd_____|HiReg/BX
 __6_|_0___1___0___0___1_|____Rd_____|_____________Word______________|LDR PC
 __7_|_0___1___0___1_|__Op___|_0_|___Ro______|____Rb_____|____Rd_____|LDR/STR
 __8_|_0___1___0___1_|__Op___|_1_|___Ro______|____Rb_____|____Rd_____|""H/SB/SH
 __9_|_0___1___1_|__Op___|_______Offset______|____Rb_____|____Rd_____|""{B}
 _10_|_1___0___0___0_|Op_|_______Offset______|____Rb_____|____Rd_____|""H
 _11_|_1___0___0___1_|Op_|____Rd_____|_____________Word______________|"" SP
 _12_|_1___0___1___0_|Op_|____Rd_____|_____________Word______________|ADD PC/SP
 _13_|_1___0___1___1___0___0___0___0_|_S_|___________Word____________|ADD SP,nn
 _14_|_1___0___1___1_|Op_|_1___0_|_R_|____________Rlist______________|PUSH/POP
 _17_|_1___0___1___1___1___1___1___0_|___________User_Data___________|BKPT ARM9
 _15_|_1___1___0___0_|Op_|____Rb_____|____________Rlist______________|STM/LDM
 _16_|_1___1___0___1_|_____Cond______|_________Signed_Offset_________|B{cond}
 _U__|_1___1___0___1___1___1___1___0_|_____________var_______________|UNDEF ARM9
 _17_|_1___1___0___1___1___1___1___1_|___________User_Data___________|SWI
 _18_|_1___1___1___0___0_|________________Offset_____________________|B
 _19_|_1___1___1___0___1_|_________________________var___________|_0_|BLXsuf ARM9
 _U__|_1___1___1___0___1_|_________________________var___________|_1_|UNDEF ARM9
 _19_|_1___1___1___1_|_H_|______________Offset_Low/High______________|BL (BLX ARM9)
</PRE></TD></TR></TBODY></TABLE><BR><BR>Further UNDEFS ??? ARM9?<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> 1011 0001 xxxxxxxx (reserved)
 1011 0x1x xxxxxxxx (reserved)
 1011 10xx xxxxxxxx (reserved)
 1011 1111 xxxxxxxx (reserved)
 1101 1110 xxxxxxxx (free for user)
</PRE></TD></TR></TBODY></TABLE><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb1moveshiftedregister></A><FONT size=+2>&nbsp;THUMB.1: 
      move shifted register</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-13  Must be 000b for 'move shifted register' instructions
  12-11  Opcode
           00b: LSL Rd,Rs,#Offset   (logical/arithmetic shift left)
           01b: LSR Rd,Rs,#Offset   (logical    shift right)
           10b: ASR Rd,Rs,#Offset   (arithmetic shift right)
           11b: Reserved (used for add/subtract instructions)
  10-6   Offset                     (0-31)
  5-3    Rs - Source register       (R0..R7)
  2-0    Rd - Destination register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Example: LSL Rd,Rs,#nn ; Rd = Rs &lt;&lt; nn ; 
ARM equivalent: MOVS Rd,Rs,LSL #nn<BR>Zero shift amount is having special 
meaning (same as for ARM shifts), LSL#0 performs no shift (the the carry flag 
remains unchanged), LSR/ASR#0 are interpreted as LSR/ASR#32. Attempts to specify 
LSR/ASR#0 in source code are automatically redirected as LSL#0, and source 
LSR/ASR#32 is redirected as opcode LSR/ASR#0.<BR>Execution Time: 1S<BR>Flags: 
Z=zeroflag, N=sign, C=carry (except LSL#0: C=unchanged), 
V=unchanged.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb2addsubtract></A><FONT size=+2>&nbsp;THUMB.2: 
      add/subtract</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-11  Must be 00011b for 'add/subtract' instructions
  10-9   Opcode (0-3)
           0: ADD Rd,Rs,Rn   ;add register        Rd=Rs+Rn
           1: SUB Rd,Rs,Rn   ;subtract register   Rd=Rs-Rn
           2: ADD Rd,Rs,#nn  ;add immediate       Rd=Rs+nn
           3: SUB Rd,Rs,#nn  ;subtract immediate  Rd=Rs-nn
         Pseudo/alias opcode with Imm=0:
           2: MOV Rd,Rs      ;move (affects cpsr) Rd=Rs+0
  8-6    For Register Operand:
           Rn - Register Operand (R0..R7)
         For Immediate Operand:
           nn - Immediate Value  (0-7)
  5-3    Rs - Source register       (R0..R7)
  2-0    Rd - Destination register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Return: Rd contains result, N,Z,C,V affected 
(including MOV).<BR>Execution Time: 1S<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb3movecompareaddsubtractimmediate></A><FONT 
      size=+2>&nbsp;THUMB.3: move/compare/add/subtract 
  immediate</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-13  Must be 001b for this type of instructions
  12-11  Opcode
           00b: MOV Rd,#nn      ;move     Rd   = #nn
           01b: CMP Rd,#nn      ;compare  Void = Rd - #nn
           10b: ADD Rd,#nn      ;add      Rd   = Rd + #nn
           11b: SUB Rd,#nn      ;subtract Rd   = Rd - #nn
  10-8   Rd - Destination Register  (R0..R7)
  7-0    nn - Unsigned Immediate    (0-255)
</PRE></TD></TR></TBODY></TABLE>ARM equivalents for MOV/CMP/ADD/SUB are 
MOVS/CMP/ADDS/SUBS same format.<BR>Execution Time: 1S<BR>Return: Rd contains 
result (except CMP), N,Z,C,V affected (for MOV only N,Z).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb4aluoperations></A><FONT size=+2>&nbsp;THUMB.4: ALU 
      operations</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-10  Must be 010000b for this type of instructions
  9-6    Opcode (0-Fh)
           0: AND Rd,Rs     ;AND logical       Rd = Rd AND Rs
           1: EOR Rd,Rs     ;XOR logical       Rd = Rd XOR Rs
           2: LSL Rd,Rs     ;log. shift left   Rd = Rd &lt;&lt; (Rs AND 0FFh)
           3: LSR Rd,Rs     ;log. shift right  Rd = Rd &gt;&gt; (Rs AND 0FFh)
           4: ASR Rd,Rs     ;arit shift right  Rd = Rd SAR (Rs AND 0FFh)
           5: ADC Rd,Rs     ;add with carry    Rd = Rd + Rs + Cy
           6: SBC Rd,Rs     ;sub with carry    Rd = Rd - Rs - NOT Cy
           7: ROR Rd,Rs     ;rotate right      Rd = Rd ROR (Rs AND 0FFh)
           8: TST Rd,Rs     ;test            Void = Rd AND Rs
           9: NEG Rd,Rs     ;negate            Rd = 0 - Rs
           A: CMP Rd,Rs     ;compare         Void = Rd - Rs
           B: CMN Rd,Rs     ;neg.compare     Void = Rd + Rs
           C: ORR Rd,Rs     ;OR logical        Rd = Rd OR Rs
           D: MUL Rd,Rs     ;multiply          Rd = Rd * Rs
           E: BIC Rd,Rs     ;bit clear         Rd = Rd AND NOT Rs
           F: MVN Rd,Rs     ;not               Rd = NOT Rs
  5-3    Rs - Source Register       (R0..R7)
  2-0    Rd - Destination Register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>ARM equivalent for NEG would be RSBS.<BR>Return: 
Rd contains result (except TST,CMP,CMN),<BR>Affected Flags:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  N,Z,C,V for  ADC,SBC,NEG,CMP,CMN
  N,Z,C   for  LSL,LSR,ASR,ROR (carry flag unchanged if zero shift amount)
  N,Z,C   for  MUL on ARMv4 and below: carry flag destroyed
  N,Z     for  MUL on ARMv5 and above: carry flag unchanged
  N,Z     for  AND,EOR,TST,ORR,BIC,MVN
</PRE></TD></TR></TBODY></TABLE>Execution Time:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1S      for  AND,EOR,ADC,SBC,TST,NEG,CMP,CMN,ORR,BIC,MVN
  1S+1I   for  LSL,LSR,ASR,ROR
  1S+mI   for  MUL on ARMv4 (m=1..4; depending on MSBs of incoming Rd value)
  1S+mI   for  MUL on ARMv5 (m=3; fucking slow, no matter of MSBs of Rd value)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb5hiregisteroperationsbranchexchange></A><FONT 
      size=+2>&nbsp;THUMB.5: Hi register operations/branch 
  exchange</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-10  Must be 010001b for this type of instructions
  9-8    Opcode (0-3)
           0: ADD Rd,Rs   ;add        Rd = Rd+Rs
           1: CMP Rd,Rs   ;compare  Void = Rd-Rs  ;CPSR affected
           2: MOV Rd,Rs   ;move       Rd = Rs
           2: NOP         ;nop        R8 = R8
           3: BX  Rs      ;jump       PC = Rs     ;may switch THUMB/ARM
           3: BLX Rs      ;call       PC = Rs     ;may switch THUMB/ARM (ARM9)
  7      MSBd - Destination Register most significant bit (or BL/BLX flag)
  6      MSBs - Source Register most significant bit
  5-3    Rs - Source Register        (together with MSBs: R0..R15)
  2-0    Rd - Destination Register   (together with MSBd: R0..R15)
</PRE></TD></TR></TBODY></TABLE>Restrictions: For ADD/CMP/MOV, MSBs and/or MSBd 
must be set, ie. it is not allowed that both are cleared.<BR>When using R15 (PC) 
as operand, the value will be the address of the instruction plus 4 (ie. $+4). 
Except for BX R15: CPU switches to ARM state, and PC is auto-aligned as (($+4) 
AND NOT 2).<BR>For BX, MSBs may be 0 or 1, MSBd must be zero, Rd is not 
used/zero.<BR>For BLX, MSBs may be 0 or 1, MSBd must be set, Rd is not 
used/zero.<BR>For BX/BLX, when Bit 0 of the value in Rs is zero:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Processor will be switched into ARM mode!
  If so, Bit 1 of Rs must be cleared (32bit word aligned).
  Thus, BX PC (switch to ARM) may be issued from word-aligned address
  only, the destination is PC+4 (ie. the following halfword is skipped).
</PRE></TD></TR></TBODY></TABLE>BLX may not use R15. BLX saves the return 
address as LR=PC+3 (with thumb bit).<BR>Assemblers/Disassemblers should use MOV 
R8,R8 as NOP (in THUMB mode).<BR>Return: Only CMP affects CPSR condition 
flags!<BR>Execution Time:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> 1S     for ADD/MOV/CMP
 2S+1N  for ADD/MOV with Rd=R15, and for BX
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb6loadpcrelative></A><FONT size=+2>&nbsp;THUMB.6: load 
      PC-relative</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-11  Must be 01001b for this type of instructions
  N/A    Opcode (fixed)
           LDR Rd,[PC,#nn]      ;load 32bit    Rd = WORD[PC+nn]
  10-8   Rd - Destination Register   (R0..R7)
  7-0    nn - Unsigned offset        (0-1020 in steps of 4)
</PRE></TD></TR></TBODY></TABLE>The value of PC will be interpreted as (($+4) 
AND NOT 2).<BR>Return: No flags affected, data loaded into Rd.<BR>Execution 
Time: 1S+1N+1I<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb7loadstorewithregisteroffset></A><FONT 
      size=+2>&nbsp;THUMB.7: load/store with register 
offset</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 0101b for this type of instructions
  11-10  Opcode (0-3)
          0: STR  Rd,[Rb,Ro]   ;store 32bit data  WORD[Rb+Ro] = Rd
          1: STRB Rd,[Rb,Ro]   ;store  8bit data  BYTE[Rb+Ro] = Rd
          2: LDR  Rd,[Rb,Ro]   ;load  32bit data  Rd = WORD[Rb+Ro]
          3: LDRB Rd,[Rb,Ro]   ;load   8bit data  Rd = BYTE[Rb+Ro]
  9      Must be zero (0) for this type of instructions
  8-6    Ro - Offset Register              (R0..R7)
  5-3    Rb - Base Register                (R0..R7)
  2-0    Rd - Source/Destination Register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, data loaded either 
into Rd or into memory.<BR>Execution Time: 1S+1N+1I for LDR, or 2N for 
STR<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb8loadstoresignextendedbytehalfword></A><FONT 
      size=+2>&nbsp;THUMB.8: load/store sign-extended 
  byte/halfword</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 0101b for this type of instructions
  11-10  Opcode (0-3)
          0: STRH Rd,[Rb,Ro]  ;store 16bit data          HALFWORD[Rb+Ro] = Rd
          1: LDSB Rd,[Rb,Ro]  ;load sign-extended 8bit   Rd = BYTE[Rb+Ro]
          2: LDRH Rd,[Rb,Ro]  ;load zero-extended 16bit  Rd = HALFWORD[Rb+Ro]
          3: LDSH Rd,[Rb,Ro]  ;load sign-extended 16bit  Rd = HALFWORD[Rb+Ro]
  9      Must be set (1) for this type of instructions
  8-6    Ro - Offset Register              (R0..R7)
  5-3    Rb - Base Register                (R0..R7)
  2-0    Rd - Source/Destination Register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, data loaded either 
into Rd or into memory.<BR>Execution Time: 1S+1N+1I for LDR, or 2N for 
STR<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb9loadstorewithimmediateoffset></A><FONT 
      size=+2>&nbsp;THUMB.9: load/store with immediate 
  offset</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-13  Must be 011b for this type of instructions
  12-11  Opcode (0-3)
          0: STR  Rd,[Rb,#nn]  ;store 32bit data   WORD[Rb+nn] = Rd
          1: LDR  Rd,[Rb,#nn]  ;load  32bit data   Rd = WORD[Rb+nn]
          2: STRB Rd,[Rb,#nn]  ;store  8bit data   BYTE[Rb+nn] = Rd
          3: LDRB Rd,[Rb,#nn]  ;load   8bit data   Rd = BYTE[Rb+nn]
  10-6   nn - Unsigned Offset              (0-31 for BYTE, 0-124 for WORD)
  5-3    Rb - Base Register                (R0..R7)
  2-0    Rd - Source/Destination Register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, data loaded either 
into Rd or into memory.<BR>Execution Time: 1S+1N+1I for LDR, or 2N for 
STR<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb10loadstorehalfword></A><FONT size=+2>&nbsp;THUMB.10: 
      load/store halfword</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1000b for this type of instructions
  11     Opcode (0-1)
          0: STRH Rd,[Rb,#nn]  ;store 16bit data   HALFWORD[Rb+nn] = Rd
          1: LDRH Rd,[Rb,#nn]  ;load  16bit data   Rd = HALFWORD[Rb+nn]
  10-6   nn - Unsigned Offset              (0-62, step 2)
  5-3    Rb - Base Register                (R0..R7)
  2-0    Rd - Source/Destination Register  (R0..R7)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, data loaded either 
into Rd or into memory.<BR>Execution Time: 1S+1N+1I for LDR, or 2N for 
STR<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb11loadstoresprelative></A><FONT size=+2>&nbsp;THUMB.11: 
      load/store SP-relative</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1001b for this type of instructions
  11     Opcode (0-1)
          0: STR  Rd,[SP,#nn]  ;store 32bit data   WORD[SP+nn] = Rd
          1: LDR  Rd,[SP,#nn]  ;load  32bit data   Rd = WORD[SP+nn]
  10-8   Rd - Source/Destination Register  (R0..R7)
  7-0    nn - Unsigned Offset              (0-1020, step 4)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, data loaded either 
into Rd or into memory.<BR>Execution Time: 1S+1N+1I for LDR, or 2N for 
STR<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb12getrelativeaddress></A><FONT size=+2>&nbsp;THUMB.12: 
      get relative address</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1010b for this type of instructions
  11     Opcode/Source Register (0-1)
          0: ADD  Rd,PC,#nn    ;Rd = (($+4) AND NOT 2) + nn
          1: ADD  Rd,SP,#nn    ;Rd = SP + nn
  10-8   Rd - Destination Register         (R0..R7)
  7-0    nn - Unsigned Offset              (0-1020, step 4)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, result in 
Rd.<BR>Execution Time: 1S<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb13addoffsettostackpointer></A><FONT 
      size=+2>&nbsp;THUMB.13: add offset to stack 
pointer</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-8   Must be 10110000b for this type of instructions
  7      Opcode/Sign
          0: ADD  SP,#nn       ;SP = SP + nn
          1: ADD  SP,#-nn      ;SP = SP - nn
  6-0    nn - Unsigned Offset    (0-508, step 4)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, SP 
adjusted.<BR>Execution Time: 1S<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb14pushpopregisters></A><FONT size=+2>&nbsp;THUMB.14: 
      push/pop registers</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1011b for this type of instructions
  11     Opcode (0-1)
          0: PUSH {Rlist}{LR}   ;store in memory, decrements SP (R13)
          1: POP  {Rlist}{PC}   ;load from memory, increments SP (R13)
  10-9   Must be 10b for this type of instructions
  8      PC/LR Bit (0-1)
          0: No
          1: PUSH LR (R14), or POP PC (R15)
  7-0    Rlist - List of Registers (R7..R0)
</PRE></TD></TR></TBODY></TABLE>In THUMB mode stack is always meant to be 'full 
descending', ie. PUSH is equivalent to 'STMFD/STMDB' and POP to 'LDMFD/LDMIA' in 
ARM mode.<BR><BR>Examples:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> PUSH {R0-R3}     ;push R0,R1,R2,R3
 PUSH {R0,R2,LR}  ;push R0,R2,LR
 POP  {R4,R7}     ;pop R4,R7
 POP  {R2-R4,PC}  ;pop R2,R3,R4,PC
</PRE></TD></TR></TBODY></TABLE>Note: When calling to a sub-routine, the return 
address is stored in LR register, when calling further sub-routines, PUSH {LR} 
must be used to save higher return address on stack. If so, POP {PC} can be 
later used to return from the sub-routine.<BR>POP {PC} ignores the least 
significant bit of the return address (processor remains in thumb state even if 
bit0 was cleared), when intending to return with optional mode switch, use a 
POP/BX combination (eg. POP {R3} / BX R3).<BR>ARM9: POP {PC} copies the LSB to 
thumb bit (switches to ARM if bit0=0).<BR>Return: No flags affected, SP 
adjusted, registers loaded/stored.<BR>Execution Time: nS+1N+1I (POP), 
(n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb15multipleloadstore></A><FONT size=+2>&nbsp;THUMB.15: 
      multiple load/store</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1100b for this type of instructions
  11     Opcode (0-1)
          0: STMIA Rb!,{Rlist}   ;store in memory, increments Rb
          1: LDMIA Rb!,{Rlist}   ;load from memory, increments Rb
  10-8   Rb - Base register (modified) (R0-R7)
  7-0    Rlist - List of Registers     (R7..R0)
</PRE></TD></TR></TBODY></TABLE>Both STM and LDM are incrementing the Base 
Register.<BR>The lowest register in the list (ie. R0, if it's in the list) is 
stored/loaded at the lowest memory address.<BR>Examples:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> STMIA R7!,{R0-R2}  ;store R0,R1,R2
 LDMIA R0!,{R1,R5}  ;store R1,R5
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, Rb adjusted, 
registers loaded/stored.<BR>Execution Time: nS+1N+1I for LDM, or (n-1)S+2N for 
STM.<BR><BR><B>Strange Effects on Invalid Rlist's</B><BR>Empty Rlist: R15 
loaded/stored (ARMv4 only), and Rb=Rb+40h (ARMv4-v5).<BR>Writeback with Rb 
included in Rlist: Store OLD base if Rb is FIRST entry in Rlist, otherwise store 
NEW base (STM/ARMv4), always store OLD base (STM/ARMv5), no writeback 
(LDM/ARMv4/ARMv5; at this point, THUMB opcodes work different than ARM 
opcodes).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb16conditionalbranch></A><FONT size=+2>&nbsp;THUMB.16: 
      conditional branch</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-12  Must be 1101b for this type of instructions
  11-8   Opcode/Condition (0-Fh)
          0: BEQ label   ;Z=1         ;equal (zero)
          1: BNE label   ;Z=0         ;not equal (nonzero)
          2: BCS label   ;C=1         ;unsigned higher or same (carry set)
          3: BCC label   ;C=0         ;unsigned lower (carry cleared)
          4: BMI label   ;N=1         ;negative (minus)
          5: BPL label   ;N=0         ;positive or zero (plus)
          6: BVS label   ;V=1         ;overflow (V set)
          7: BVC label   ;V=0         ;no overflow (V cleared)
          8: BHI label   ;C=1 and Z=0 ;unsigned higher
          9: BLS label   ;C=0 or Z=1  ;unsigned lower or same
          A: BGE label   ;N=V         ;greater or equal
          B: BLT label   ;N&lt;&gt;V        ;less than
          C: BGT label   ;Z=0 and N=V ;greater than
          D: BLE label   ;Z=1 or N&lt;&gt;V ;less or equal
          E: Undefined, should not be used
          F: Reserved for SWI instruction (see SWI opcode)
  7-0    Signed Offset, step 2 ($+4-256..$+4+254)
</PRE></TD></TR></TBODY></TABLE>Destination address must by halfword aligned 
(ie. bit 0 cleared)<BR>Return: No flags affected, PC adjusted if condition 
true<BR>Execution Time:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2S+1N   if condition true (jump executed)
  1S      if condition false
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb17softwareinterruptandbreakpoint></A><FONT 
      size=+2>&nbsp;THUMB.17: software interrupt and 
  breakpoint</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-8   Opcode
          11011111b: SWI nn   ;software interrupt
          10111110b: BKPT nn  ;software breakpoint (ARMv5 and up)
  7-0    nn - Comment Immediate    (0-255)
</PRE></TD></TR></TBODY></TABLE>SWI supposed for calls to the operating system - 
Enter Supervisor mode (SVC) in ARM state. BKPT intended for debugging - enters 
Abort mode in ARM state via Prefetch Abort vector.<BR><BR>Execution 
SWI/BKPT:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R14_svc=PC+2     R14_abt=PC+4   ;save return address
  SPSR_svc=CPSR    SPSR_abt=CPSR  ;save CPSR flags
  CPSR=&lt;changed&gt;   CPSR=&lt;changed&gt; ;Enter svc/abt, ARM state, IRQs disabled
  PC=VVVV0008h     PC=VVVV000Ch   ;jump to SWI/PrefetchAbort vector address
</PRE></TD></TR></TBODY></TABLE>Execution Time: 2S+1N<BR><BR>Interpreting the 
Comment Field:<BR>The immediate parameter is ignored by the processor, the user 
interrupt handler may read-out this number by examining the lower 8bit of the 
16bit opcode opcode at [R14_svc-2]. In case that your program executes SWI's 
from inside of ARM mode also: Your SWI handler must then examine the T Bit 
SPSR_svc in order to determine whether it's been a ARM SWI - if so, examining 
the lower 24bit of the 32bit opcode opcode at [R14_svc-4].<BR><BR>For Returning 
from SWI use this instruction:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MOVS PC,R14
</PRE></TD></TR></TBODY></TABLE>That instructions does both restoring PC and 
CPSR, ie. PC=R14_svc, and CPSR=SPRS_svc. In this case (as called from THUMB 
mode), this does also include restoring THUMB mode.<BR><BR>Nesting 
SWIs:<BR>SPSR_svc and R14_svc should be saved on stack before either invoking 
nested SWIs, or (if the IRQ handler uses SWIs) before enabling IRQs.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb18unconditionalbranch></A><FONT size=+2>&nbsp;THUMB.18: 
      unconditional branch</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-11  Must be 11100b for this type of instructions
  N/A    Opcode (fixed)
          B label   ;branch (jump)
  10-0   Signed Offset, step 2 ($+4-2048..$+4+2046)
</PRE></TD></TR></TBODY></TABLE>Return: No flags affected, PC 
adjusted.<BR>Execution Time: 2S+1N<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=thumb19longbranchwithlink></A><FONT size=+2>&nbsp;THUMB.19: 
      long branch with link</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>This may be used to call (or jump) to a subroutine, return address 
is saved in LR (R14).<BR>Unlike all other THUMB mode instructions, this 
instruction occupies 32bit of memory which are split into two 16bit THUMB 
opcodes.<BR><BR>First Instruction - LR = PC+4+(nn SHL 12)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-11  Must be 11110b for BL/BLX type of instructions
  10-0   nn - Upper 11 bits of Target Address
</PRE></TD></TR></TBODY></TABLE>Second Instruction - PC = LR + (nn SHL 1), and 
LR = PC+2 OR 1 (and BLX: T=0)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  15-11  Opcode
          11111b: BL label   ;branch long with link
          11101b: BLX label  ;branch long with link switch to ARM mode (ARM9)
  10-0   nn - Lower 11 bits of Target Address (BLX: Bit0 Must be zero)
</PRE></TD></TR></TBODY></TABLE><BR>The destination address range is 
(PC+4)-400000h..+3FFFFEh, ie. PC+/-4M.<BR>Target must be halfword-aligned. As 
Bit 0 in LR is set, it may be used to return by a BX LR instruction (keeping CPU 
in THUMB mode).<BR>Return: No flags affected, PC adjusted, return address in 
LR.<BR>Execution Time: 3S+1N (first opcode 1S, second opcode 
2S+1N).<BR><BR>Note<BR>Exceptions may or may not occur between first and second 
opcode, this is "implementation defined" ???<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arminstructionset></A><FONT size=+2>&nbsp;ARM Instruction 
      Set</FONT></TD></TR></TBODY></TABLE><BR>When operating in ARM state, full 32bit 
opcodes are used.<BR><BR><B>Summaries</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arminstructionsummary">ARM Instruction 
Summary</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armconditionfield">ARM Condition 
Field</A><BR><BR><B>Jumps and Calls</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm3branchandexchangebxblx">ARM.3: 
Branch and Exchange (BX, BLX)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm4branchandbranchwithlinkbblblx">ARM.4: 
Branch and Branch with Link (B, BL, BLX)</A><BR>(Also, most various ALU, LDR, 
LDM opcodes can change PC.)<BR><BR><B>Register Operations</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm5dataprocessing">ARM.5: Data 
Processing</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm6psrtransfermrsmsr">ARM.6: PSR 
Transfer (MRS, MSR)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm7multiplyandmultiplyaccumulatemulmla">ARM.7: 
Multiply and Multiply-Accumulate (MUL,MLA)</A><BR><BR><B>Memory Addressing 
Operations</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm9singledatatransferldrstrpld">ARM.9: 
Single Data Transfer (LDR, STR, PLD)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm10halfworddoublewordandsigneddatatransfer">ARM.10: 
Halfword, Doubleword, and Signed Data Transfer</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm11blockdatatransferldmstm">ARM.11: 
Block Data Transfer (LDM,STM)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm12singledataswapswp">ARM.12: Single 
Data Swap (SWP)</A><BR><BR><B>Exception Calls and Coprocessor</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm13softwareinterruptswibkpt">ARM.13: 
Software Interrupt (SWI,BKPT)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm14coprocessordataoperationscdp">ARM.14: 
Coprocessor Data Operations (CDP)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm15coprocessordatatransfersldcstc">ARM.15: 
Coprocessor Data Transfers (LDC,STC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm16coprocessorregistertransfersmrcmcr">ARM.16: 
Coprocessor Register Transfers (MRC, MCR)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armxcoprocessordoubleregistertransfermcrrmrrc">ARM.X: 
Coprocessor Double-Register Transfer (MCRR,MRRC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm17undefinedinstruction">ARM.17: 
Undefined Instruction</A><BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armxcountleadingzeros">ARM.X: Count 
Leading Zeros</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armxqaddqsub">ARM.X: 
QADD/QSUB</A><BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm26bitmemoryinterface">ARM 26bit 
Memory Interface</A><BR><BR><B>Note:</B><BR>Switching between ARM and THUMB 
state can be done by using the Branch and Exchange (BX) instruction.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arminstructionsummary></A><FONT size=+2>&nbsp;ARM Instruction 
      Summary</FONT></TD></TR></TBODY></TABLE><BR>Modification of CPSR flags is 
optional for all {S} instructions.<BR><BR><B>Logical Operations</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction             Cycles   Flags Format Expl.
  MOV{cond}{S} Rd,Op2      1S+x+y   NZc- 5   Rd = Op2
  MVN{cond}{S} Rd,Op2      1S+x+y   NZc- 5   Rd = NOT Op2
  AND{cond}{S} Rd,Rn,Op2   1S+x+y   NZc- 5   Rd = Rn AND Op2
  TST{cond}{P}    Rn,Op2   1S+x     NZc- 5 Void = Rn AND Op2
  EOR{cond}{S} Rd,Rn,Op2   1S+x+y   NZc- 5   Rd = Rn XOR Op2
  TEQ{cond}{P}    Rn,Op2   1S+x     NZc- 5 Void = Rn XOR Op2
  ORR{cond}{S} Rd,Rn,Op2   1S+x+y   NZc- 5   Rd = Rn OR Op2
  BIC{cond}{S} Rd,Rn,Op2   1S+x+y   NZc- 5   Rd = Rn AND NOT Op2
</PRE></TD></TR></TBODY></TABLE>Add x=1I cycles if Op2 shifted-by-register. Add 
y=1S+1N cycles if Rd=R15.<BR>Carry flag affected only if Op2 contains a non-zero 
shift amount.<BR><BR><B>Arithmetic Operations</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction             Cycles  Flags Format Expl.
  ADD{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Rn+Op2
  ADC{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Rn+Op2+Cy
  SUB{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Rn-Op2
  SBC{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Rn-Op2+Cy-1
  RSB{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Op2-Rn
  RSC{cond}{S} Rd,Rn,Op2   1S+x+y   NZCV 5   Rd = Op2-Rn+Cy-1
  CMP{cond}{P}    Rn,Op2   1S+x     NZCV 5 Void = Rn-Op2
  CMN{cond}{P}    Rn,Op2   1S+x     NZCV 5 Void = Rn+Op2
</PRE></TD></TR></TBODY></TABLE>Add x=1I cycles if Op2 shifted-by-register. Add 
y=1S+1N cycles if Rd=R15.<BR><BR><B>Multiply</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction                     Cycles  Flags Format Expl.
  MUL{cond}{S} Rd,Rm,Rs            1S+mI     NZx- 7  Rd = Rm*Rs
  MLA{cond}{S} Rd,Rm,Rs,Rn         1S+mI+1I  NZx- 7  Rd = Rm*Rs+Rn
  UMULL{cond}{S} RdLo,RdHi,Rm,Rs   1S+mI+1I  NZx- 7  RdHiLo = Rm*Rs
  UMLAL{cond}{S} RdLo,RdHi,Rm,Rs   1S+mI+2I  NZx- 7  RdHiLo = Rm*Rs+RdHiLo
  SMULL{cond}{S} RdLo,RdHi,Rm,Rs   1S+mI+1I  NZx- 7  RdHiLo = Rm*Rs
  SMLAL{cond}{S} RdLo,RdHi,Rm,Rs   1S+mI+2I  NZx- 7  RdHiLo = Rm*Rs+RdHiLo
  SMLAxy{cond} Rd,Rm,Rs,Rn       ---q 7  Rd=HalfRm*HalfRs+Rn ARMv5TE(xP)
  SMLAWy{cond} Rd,Rm,Rs,Rn       ---q 7  Rd=(Rm*HalfRs)/10000h+Rn ARMv5TE(xP)
  SMULWy{cond} Rd,Rm,Rs          ---- 7  Rd=(Rm*HalfRs)/10000h    ARMv5TE(xP)
  SMLALxy{cond} RdLo,RdHi,Rm,Rs  ---- 7  RdHiLo=RdHiLo+HalfRm*HalfRs ARMv5TE(xP)
  SMULxy{cond} Rd,Rm,Rs          ---- 7  Rd=HalfRm*HalfRs ARMv5TE(xP)
</PRE></TD></TR></TBODY></TABLE><BR><B>Memory Load/Store</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction                     Cycles       Flags Format Expl.
  LDR{cond}{B}{T} Rd,&lt;Address&gt;     1S+1N+1I +y   ---- 9  Rd=[Rn+/-&lt;offset&gt;]
  LDR{cond}H      Rd,&lt;Address&gt;     1S+1N+1I +y   ---- 10 Load Unsigned halfword
  LDR{cond}D      Rd,&lt;Address&gt;                   ---- 10 Load Dword ARMv5TE
  LDR{cond}SB     Rd,&lt;Address&gt;     1S+1N+1I +y   ---- 10 Load Signed byte
  LDR{cond}SH     Rd,&lt;Address&gt;     1S+1N+1I +y   ---- 10 Load Signed halfword
  LDM{cond}{amod} Rn{!},&lt;Rlist&gt;{^} nS+1N+1I +y   ---- 11 Load Multiple
  STR{cond}{B}{T} Rd,&lt;Address&gt;     2N            ---- 9  [Rn+/-&lt;offset&gt;]=Rd
  STR{cond}H      Rd,&lt;Address&gt;     2N            ---- 10 Store halfword
  STR{cond}D      Rd,&lt;Address&gt;                   ---- 10 Store Dword ARMv5TE
  STM{cond}{amod} Rn{!},&lt;Rlist&gt;{^} (n-1)S+2N     ---- 11 Store Multiple
  SWP{cond}{B}    Rd,Rm,[Rn]       1S+2N+1I      ---- 12 Rd=[Rn], [Rn]=Rm
  PLD             &lt;Address&gt;        1S            ---- 9  Prepare Cache ARMv5TE
</PRE></TD></TR></TBODY></TABLE>For LDR/LDM, add y=1S+1N if Rd=R15, or if R15 in 
Rlist.<BR><BR><B>Jumps, Calls, CPSR Mode, and others</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction              Cycles  Flags Format Expl.
  B{cond}   label           2S+1N    ---- 4   PC=$+8+/-32M
  BL{cond}  label           2S+1N    ---- 4   PC=$+8+/-32M, LR=$+4
  BX{cond}  Rn              2S+1N    ---- 3   PC=Rn, T=Rn.0 (THUMB/ARM)
  BLX{cond} Rn              2S+1N    ---- 3   PC=Rn, T=Rn.0, LR=PC+4, ARM9
  BLX       label           2S+1N    ---- 3   PC=PC+$+/-32M, LR=$+4, T=1, ARM9
  MRS{cond} Rd,Psr          1S       ---- 6   Rd=Psr
  MSR{cond} Psr{_field},Op  1S      (psr) 6   Psr[field]=Op
  SWI{cond} Imm24bit        2S+1N    ---- 13  PC=8, ARM Svc mode, LR=$+4
  BKPT      Imm16bit        ???      ---- ??? PC=C, ARM Abt mode, LR=$+4 ARM9
  The Undefined Instruction 2S+1I+1N ---- 17  PC=4, ARM Und mode, LR=$+4
  cond=false                1S       ---- ..  Any opcode with condition=false
  NOP                       1S       ---- 5   R0=R0
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  CLZ{cond} Rd,Rm           ???      ---- ??? Count Leading Zeros ARMv5
  QADD{cond} Rd,Rm,Rn            ---q   Rd=Rm+Rn       ARMv5TE(xP)
  QSUB{cond} Rd,Rm,Rn            ---q   Rd=Rm-Rn       ARMv5TE(xP)
  QDADD{cond} Rd,Rm,Rn           ---q   Rd=Rm+Rn*2     ARMv5TE(xP)
  QDSUB{cond} Rd,Rm,Rn           ---q   Rd=Rm-Rn*2     ARMv5TE(xP)
</PRE></TD></TR></TBODY></TABLE><BR><B>Coprocessor Functions (if any)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Instruction                         Cycles  Flags Format Expl.
  CDP{cond} Pn,&lt;cpopc&gt;,Cd,Cn,Cm{,&lt;cp&gt;} 1S+bI   ---- 14 Coprocessor specific
  STC{cond}{L} Pn,Cd,&lt;Address&gt;         (n-1)S+2N+bI 15 [address] = CRd
  LDC{cond}{L} Pn,Cd,&lt;Address&gt;         (n-1)S+2N+bI 15 CRd = [address]
  MCR{cond} Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;} 1S+bI+1C     16 CRn = Rn {&lt;op&gt; CRm}
  MRC{cond} Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;} 1S+(b+1)I+1C 16 Rn = CRn {&lt;op&gt; CRm}
  CDP2,STC2,LDC2,MCR2,MRC2 - ARMv5 Extensions similar above, without {cond}
  MCRR{cond} Pn,&lt;cpopc&gt;,Rd,Rn,Cm  ;write Rd,Rn to coproc ARMv5TE
  MRRC{cond} Pn,&lt;cpopc&gt;,Rd,Rn,Cm  ;read Rd,Rn from coproc ARMv5TE
</PRE></TD></TR></TBODY></TABLE><BR>Note that no sections 1-2 exist, that is 
because the sections numbers comply with chapter numbers of the official ARM 
docs, which described ARM opcodes in chapter 3-17.<BR><BR><B>ARM Binary Opcode 
Format</B><BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  |..3 ..................2 ..................1 ..................0|
  |1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0_9_8_7_6_5_4_3_2_1_0|
  |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| DataProc
  |_Cond__|0_0_0|___Op__|S|__Rn___|__Rd___|__Rs___|0|Typ|1|__Rm___| DataProc
  |_Cond__|0_0_1|___Op__|S|__Rn___|__Rd___|_Shift_|___Immediate___| DataProc
  |_Cond__|0_0_1_1_0|P|1|0|_Field_|__Rd___|_Shift_|___Immediate___| PSR Imm
  |_Cond__|0_0_0_1_0|P|L|0|_Field_|__Rd___|0_0_0_0|0_0_0_0|__Rm___| PSR Reg
  |_Cond__|0_0_0_1_0_0_1_0_1_1_1_1_1_1_1_1_1_1_1_1|0_0|L|1|__Rn___| BX,BLX
  |1_1_1_0|0_0_0_1_0_0_1_0|_____immediate_________|0_1_1_1|_immed_| BKPT ARM9
  |_Cond__|0_0_0_1_0_1_1_0_1_1_1_1|__Rd___|1_1_1_1|0_0_0_1|__Rm___| CLZ ARM9
  |_Cond__|0_0_0_1_0|Op_|0|__Rn___|__Rd___|0_0_0_0|0_1_0_1|__Rm___| QALU ARM9
  |_Cond__|0_0_0_0_0_0|A|S|__Rd___|__Rn___|__Rs___|1_0_0_1|__Rm___| Multiply
  |_Cond__|0_0_0_0_1|U|A|S|_RdHi__|_RdLo__|__Rs___|1_0_0_1|__Rm___| MulLong
  |_Cond__|0_0_0_1_0|Op_|0|Rd/RdHi|Rn/RdLo|__Rs___|1|y|x|0|__Rm___| MulHalf
  |_Cond__|0_0_0_1_0|B|0_0|__Rn___|__Rd___|0_0_0_0|1_0_0_1|__Rm___| TransSwp12
  |_Cond__|0_0_0|P|U|0|W|L|__Rn___|__Rd___|0_0_0_0|1|S|H|1|__Rm___| TransReg10
  |_Cond__|0_0_0|P|U|1|W|L|__Rn___|__Rd___|OffsetH|1|S|H|1|OffsetL| TransImm10
  |_Cond__|0_1_0|P|U|B|W|L|__Rn___|__Rd___|_________Offset________| TransImm9
  |_Cond__|0_1_1|P|U|B|W|L|__Rn___|__Rd___|__Shift__|Typ|0|__Rm___| TransReg9
  |_Cond__|0_1_1|________________xxx____________________|1|__xxx__| Undefined
  |_Cond__|1_0_0|P|U|S|W|L|__Rn___|__________Register_List________| BlockTrans
  |_Cond__|1_0_1|L|___________________Offset______________________| B,BL,BLX
  |_Cond__|1_1_0|P|U|N|W|L|__Rn___|__CRd__|__CP#__|____Offset_____| CoDataTrans
  |_Cond__|1_1_0_0_0_1_0|L|__Rn___|__Rd___|__CP#__|_CPopc_|__CRm__| CoRR ARM9
  |_Cond__|1_1_1_0|_CPopc_|__CRn__|__CRd__|__CP#__|_CP__|0|__CRm__| CoDataOp
  |_Cond__|1_1_1_0|CPopc|L|__CRn__|__Rd___|__CP#__|_CP__|1|__CRm__| CoRegTrans
  |_Cond__|1_1_1_1|_____________Ignored_by_Processor______________| SWI
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armconditionfield></A><FONT size=+2>&nbsp;ARM Condition 
      Field</FONT></TD></TR></TBODY></TABLE><BR>In ARM mode, all instructions can be 
conditionally executed depending on the state of the CPSR flags (C,N,Z,V). The 
respective suffixes {cond} must be appended to the mnemonics. For example: BEQ = 
Branch if Equal, MOVMI = Move if Signed.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Code Suffix Flags         Meaning</B>
  0:   EQ     Z=1           equal (zero)
  1:   NE     Z=0           not equal (nonzero)
  2:   CS     C=1           unsigned higher or same (carry set)
  3:   CC     C=0           unsigned lower (carry cleared)
  4:   MI     N=1           negative (minus)
  5:   PL     N=0           positive or zero (plus)
  6:   VS     V=1           overflow (V set)
  7:   VC     V=0           no overflow (V cleared)
  8:   HI     C=1 and Z=0   unsigned higher
  9:   LS     C=0 or Z=1    unsigned lower or same
  A:   GE     N=V           greater or equal
  B:   LT     N&lt;&gt;V          less than
  C:   GT     Z=0 and N=V   greater than
  D:   LE     Z=1 or N&lt;&gt;V   less or equal
  E:   AL     -             always
  F:   NV     -             never (ARMv1,v2 only) (Reserved ARMv3 and up)
</PRE></TD></TR></TBODY></TABLE><BR>To define a non-conditional instruction 
which is always to be executed (regardless of any flags), the AL suffix may be 
used - that is the same as if no suffix is specified. For example, MOVAL would 
be usually abbreviated to MOV.<BR><BR>ARMv5 and up includes a few additional 
opcodes without condition field and which cannot be made conditional, these 
opcodes are: BKPT, PLD, CDP2, LDC2, MCR2, MRC2, STC2, and BLX_imm (however 
BLX_reg can be conditional).<BR><BR>Execution Time: If condition=false: 1S 
cycle.<BR>Otherwise as specified for the respective opcode.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm3branchandexchangebxblx></A><FONT size=+2>&nbsp;ARM.3: 
      Branch and Exchange (BX, BLX)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-8   Must be "0001.0010.1111.1111.1111" for this instruction
  7-4    Opcode
          0001b: BX{cond}  Rn    ;PC=Rn, T=Rn.0  (ARMv4T and ARMv5 and up)
          0011b: BLX{cond} Rn    ;PC=Rn, T=Rn.0, LR=PC+4    (ARMv5 and up)
  3-0    Rn - Operand Register  (R0-R14)
</PRE></TD></TR></TBODY></TABLE>Switching to THUMB Mode: Set Bit 0 of the value 
in Rn to 1, program continues then at Rn-1 in THUMB mode.<BR>Results in 
undefined behaviour if using R15 (PC+8 itself) as operand.<BR>Execution Time: 2S 
+ 1N<BR>Return: No flags affected.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm4branchandbranchwithlinkbblblx></A><FONT 
      size=+2>&nbsp;ARM.4: Branch and Branch with Link (B, BL, 
  BLX)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>Branch (B) is 
supposed to jump to a subroutine. Branch with Link is meant to be used to call 
to a subroutine, return address is then saved in R14.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (must be 1111b for BLX)
  27-25  Must be "101" for this instruction
  24     Opcode (0-1) (or Halfword Offset for BLX)
          0: B{cond} label    ;branch            PC=PC+8+nn*4
          1: BL{cond} label   ;branch/link       PC=PC+8+nn*4, LR=PC+4
          H: BLX label ;ARM9  ;branch/link/thumb PC=PC+8+nn*4+H*2, LR=PC+4, T=1
  23-0   nn - Signed Offset, step 4      (-32M..+32M in steps of 4)
</PRE></TD></TR></TBODY></TABLE>Branch with Link can be used to 'call' to a 
sub-routine, which may then 'return' by MOV PC,R14 for example.<BR>Execution 
Time: 2S + 1N<BR>Return: No flags affected.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm5dataprocessing></A><FONT size=+2>&nbsp;ARM.5: Data 
      Processing</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-26  Must be 00b for this instruction
  25     I - Immediate 2nd Operand Flag (0=Register, 1=Immediate)
  24-21  Opcode (0-Fh)               ;*=Arithmetic, otherwise Logical
           0: AND{cond}{S} Rd,Rn,Op2    ;AND logical       Rd = Rn AND Op2
           1: EOR{cond}{S} Rd,Rn,Op2    ;XOR logical       Rd = Rn XOR Op2
           2: SUB{cond}{S} Rd,Rn,Op2 ;* ;subtract          Rd = Rn-Op2
           3: RSB{cond}{S} Rd,Rn,Op2 ;* ;subtract reversed Rd = Op2-Rn
           4: ADD{cond}{S} Rd,Rn,Op2 ;* ;add               Rd = Rn+Op2
           5: ADC{cond}{S} Rd,Rn,Op2 ;* ;add with carry    Rd = Rn+Op2+Cy
           6: SBC{cond}{S} Rd,Rn,Op2 ;* ;sub with carry    Rd = Rn-Op2+Cy-1
           7: RSC{cond}{S} Rd,Rn,Op2 ;* ;sub cy. reversed  Rd = Op2-Rn+Cy-1
           8: TST{cond}{P}    Rn,Op2    ;test            Void = Rn AND Op2
           9: TEQ{cond}{P}    Rn,Op2    ;test exclusive  Void = Rn XOR Op2
           A: CMP{cond}{P}    Rn,Op2 ;* ;compare         Void = Rn-Op2
           B: CMN{cond}{P}    Rn,Op2 ;* ;compare neg.    Void = Rn+Op2
           C: ORR{cond}{S} Rd,Rn,Op2    ;OR logical        Rd = Rn OR Op2
           D: MOV{cond}{S} Rd,Op2       ;move              Rd = Op2
           E: BIC{cond}{S} Rd,Rn,Op2    ;bit clear         Rd = Rn AND NOT Op2
           F: MVN{cond}{S} Rd,Op2       ;not               Rd = NOT Op2
  20     S - Set Condition Codes (0=No, 1=Yes) (Must be 1 for opcode 8-B)
  19-16  Rn - 1st Operand Register (R0..R15) (including PC=R15)
              Must be 0000b for MOV/MVN.
  15-12  Rd - Destination Register (R0..R15) (including PC=R15)
              Must be 0000b {or 1111b) for CMP/CMN/TST/TEQ{P}.
  When above Bit 25 I=0 (Register as 2nd Operand)
    When below Bit 4 R=0 - Shift by Immediate
      11-7   Is - Shift amount   (1-31, 0=Special/See below)
    When below Bit 4 R=1 - Shift by Register
      11-8   Rs - Shift register (R0-R14) - only lower 8bit 0-255 used
      7      Reserved, must be zero  (otherwise multiply or undefined opcode)
    6-5    Shift Type (0=LSL, 1=LSR, 2=ASR, 3=ROR)
    4      R - Shift by Register Flag (0=Immediate, 1=Register)
    3-0    Rm - 2nd Operand Register (R0..R15) (including PC=R15)
  When above Bit 25 I=1 (Immediate as 2nd Operand)
    11-8   Is - ROR-Shift applied to nn (0-30, in steps of 2)
    7-0    nn - 2nd Operand Unsigned 8bit Immediate
</PRE></TD></TR></TBODY></TABLE><BR><B>Second Operand (Op2)</B><BR>This may be a 
shifted register, or a shifted immediate. See Bit 25 and 11-0.<BR>Unshifted 
Register: Specify Op2 as "Rm", assembler converts to "Rm,LSL#0".<BR>Shifted 
Register: Specify as "Rm,SSS#Is" or "Rm,SSS Rs" 
(SSS=LSL/LSR/ASR/ROR).<BR>Immediate: Specify as 32bit value, for example: 
"#000NN000h", assembler should automatically convert into "#0NNh,ROR#0ssh" as 
far as possible (ie. as far as a section of not more than 8bits of the immediate 
is non-zero).<BR><BR><B>Zero Shift Amount (Shift Register by Immediate, with 
Immediate=0)</B><BR>LSL#0: No shift performed, ie. directly Op2=Rm, the C flag 
is NOT affected.<BR>LSR#0: Interpreted as LSR#32, ie. Op2 becomes zero, C 
becomes Bit 31 of Rm.<BR>ASR#0: Interpreted as ASR#32, ie. Op2 and C are filled 
by Bit 31 of Rm.<BR>ROR#0: Interpreted as RRX#1 (RCR), like ROR#1, but Op2 Bit 
31 set to old C.<BR>In source code, LSR#32, ASR#32, and RRX#1 should be 
specified as such - attempts to specify LSR#0, ASR#0, or ROR#0 will be 
internally converted to LSL#0 by the assembler.<BR><BR><B>Using R15 
(PC)</B><BR>When using R15 as Destination (Rd), note below CPSR description and 
Execution time description.<BR>When using R15 as operand (Rm or Rn), the 
returned value depends on the instruction: PC+12 if I=0,R=1 (shift by register), 
otherwise PC+8 (shift by immediate).<BR><BR><B>Returned CPSR Flags</B><BR>If 
S=1, Rd&lt;&gt;R15, logical operations (AND,EOR,TST,TEQ,ORR,MOV,BIC,MVN):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  V=not affected
  C=carryflag of shift operation (not affected if LSL#0 or Rs=00h)
  Z=zeroflag of result
  N=signflag of result (result bit 31)
</PRE></TD></TR></TBODY></TABLE>If S=1, Rd&lt;&gt;R15, arithmetic operations 
(SUB,RSB,ADD,ADC,SBC,RSC,CMP,CMN):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  V=overflowflag of result
  C=carryflag of result
  Z=zeroflag of result
  N=signflag of result (result bit 31)
</PRE></TD></TR></TBODY></TABLE>IF S=1, with unused Rd bits=1111b, {P} opcodes 
(CMPP/CMNP/TSTP/TEQP):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R15=result  ;modify PSR bits in R15, ARMv2 and below only.
  In user mode only N,Z,C,V bits of R15 can be changed.
  In other modes additionally I,F,M1,M0 can be changed.
  The PC bits in R15 are left unchanged in all modes.
</PRE></TD></TR></TBODY></TABLE>If S=1, Rd=R15; should not be used in user 
mode:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  CPSR = SPSR_&lt;current mode&gt;
  PC = result
  For example: MOVS PC,R14  ;return from SWI (PC=R14_svc, CPSR=SPSR_svc).
</PRE></TD></TR></TBODY></TABLE>If S=0: Flags are not affected (not allowed for 
CMP,CMN,TEQ,TST).<BR><BR>The instruction "MOV R0,R0" is used as "NOP" opcode in 
32bit ARM state.<BR>Execution Time: (1+p)S+rI+pN. Whereas r=1 if I=0 and R=1 
(ie. shift by register); otherwise r=0. And p=1 if Rd=R15; otherwise 
p=0.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm6psrtransfermrsmsr></A><FONT size=+2>&nbsp;ARM.6: PSR 
      Transfer (MRS, MSR)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>These instructions occupy an unused area (TEQ,TST,CMP,CMN with 
S=0) of Data Processing opcodes (ARM.5).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-26  Must be 00b for this instruction
  25     I - Immediate Operand Flag  (0=Register, 1=Immediate) (Zero for MRS)
  24-23  Must be 10b for this instruction
  22     Psr - Source/Destination PSR  (0=CPSR, 1=SPSR_&lt;current mode&gt;)
  21     Opcode
           0: MRS{cond} Rd,Psr          ;Rd = Psr
           1: MSR{cond} Psr{_field},Op  ;Psr[field] = Op
  20     Must be 0b for this instruction (otherwise TST,TEQ,CMP,CMN)
  For MRS:
    19-16   Must be 1111b for this instruction (otherwise SWP)
    15-12   Rd - Destination Register  (R0-R14)
    11-0    Not used, must be zero.
  For MSR:
    19      f  write to flags field     Bit 31-24 (aka _flg)
    18      s  write to status field    Bit 23-16 (reserved, don't change)
    17      x  write to extension field Bit 15-8  (reserved, don't change)
    16      c  write to control field   Bit 7-0   (aka _ctl)
    15-12   Not used, must be 1111b.
  For MSR Psr,Rm (I=0)
    11-4    Not used, must be zero. (otherwise BX)
    3-0     Rm - Source Register &lt;op&gt;  (R0-R14)
  For MSR Psr,Imm (I=1)
    11-8    Shift applied to Imm   (ROR in steps of two 0-30)
    7-0     Imm - Unsigned 8bit Immediate
    In source code, a 32bit immediate should be specified as operand.
    The assembler should then convert that into a shifted 8bit value.
</PRE></TD></TR></TBODY></TABLE>MSR/MRS and CPSR/SPSR supported by ARMv3 and 
up.<BR>ARMv2 and below contained PSR flags in R15, accessed by 
CMP/CMN/TST/TEQ{P}.<BR>The field mask bits specify which bits of the destination 
Psr are write-able (or write-protected), one or more of these bits should be 
set, for example, CPSR_fsxc (aka CPSR aka CPSR_all) unlocks all bits (see below 
user mode restriction though).<BR>Restrictions:<BR>In non-privileged mode (user 
mode): only condition code bits of CPSR can be changed, control bits 
can't.<BR>Only the SPSR of the current mode can be accessed; In User and System 
modes no SPSR exists.<BR>The T-bit may not be changed; for THUMB/ARM switching 
use BX instruction.<BR>Unused Bits in CPSR are reserved for future use and 
should never be changed (except for unused bits in the flags 
field).<BR>Execution Time: 1S.<BR><BR>Note: The A22i assembler recognizes MOV as 
alias for both MSR and MRS because it is practically not possible to remember 
whether MSR or MRS was the load or store opcode, and/or whether it does load to 
or from the Psr register.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm7multiplyandmultiplyaccumulatemulmla></A><FONT 
      size=+2>&nbsp;ARM.7: Multiply and Multiply-Accumulate 
  (MUL,MLA)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-25  Must be 000b for this instruction
  24-21  Opcode
          0000b: MUL{cond}{S}   Rd,Rm,Rs        ;multiply   Rd = Rm*Rs
          0001b: MLA{cond}{S}   Rd,Rm,Rs,Rn     ;mul.&amp; accumulate Rd = Rm*Rs+Rn
          0100b: UMULL{cond}{S} RdLo,RdHi,Rm,Rs ;multiply   RdHiLo=Rm*Rs
          0101b: UMLAL{cond}{S} RdLo,RdHi,Rm,Rs ;mul.&amp; acc. RdHiLo=Rm*Rs+RdHiLo
          0110b: SMULL{cond}{S} RdLo,RdHi,Rm,Rs ;sign.mul.  RdHiLo=Rm*Rs
          0111b: SMLAL{cond}{S} RdLo,RdHi,Rm,Rs ;sign.m&amp;a.  RdHiLo=Rm*Rs+RdHiLo
          1000b: SMLAxy{cond}   Rd,Rm,Rs,Rn     ;Rd=HalfRm*HalfRs+Rn
          1001b: SMLAWy{cond}   Rd,Rm,Rs,Rn     ;Rd=(Rm*HalfRs)/10000h+Rn
          1001b: SMULWy{cond}   Rd,Rm,Rs        ;Rd=(Rm*HalfRs)/10000h
          1010b: SMLALxy{cond}  RdLo,RdHi,Rm,Rs ;RdHiLo=RdHiLo+HalfRm*HalfRs
          1011b: SMULxy{cond}   Rd,Rm,Rs        ;Rd=HalfRm*HalfRs
  20     S - Set Condition Codes (0=No, 1=Yes) (Must be 0 for Halfword mul)
  19-16  Rd (or RdHi) - Destination Register (R0-R14)
  15-12  Rn (or RdLo) - Accumulate Register  (R0-R14) (Set to 0000b if unused)
  11-8   Rs - Operand Register               (R0-R14)
  For Non-Halfword Multiplies
    7-4  Must be 1001b for these instructions
  For Halfword Multiplies
    7    Must be 1 for these instructions
    6    y - Rs Top/Bottom flag (0=B=Lower 16bit, 1=T=Upper 16bit)
    5    x - Rm Top/Bottom flag (as above), or 0 for SMLAW, or 1 for SMULW
    4    Must be 0 for these instructions
  3-0    Rm - Operand Register               (R0-R14)
</PRE></TD></TR></TBODY></TABLE><BR><B>Multiply and Multiply-Accumulate 
(MUL,MLA)</B><BR>Restrictions: Rd may not be same as Rm. Rd,Rn,Rs,Rm may not be 
R15.<BR>Note: Only the lower 32bit of the internal 64bit result are stored in 
Rd, thus no sign/zero extension is required and MUL and MLA can be used for both 
signed and unsigned calculations!<BR>Execution Time: 1S+mI for MUL, and 
1S+(m+1)I for MLA. Whereas 'm' depends on whether/how many most significant bits 
of Rs are all zero or all one. That is m=1 for Bit 31-8, m=2 for Bit 31-16, m=3 
for Bit 31-24, and m=4 otherwise.<BR>Flags (if S=1): Z=zeroflag, N=signflag, 
C=destroyed (ARMv4 and below) or C=not affected (ARMv5 and up), V=not affected. 
MUL/MLA supported by ARMv2 and up.<BR><BR><B>Multiply Long and 
Multiply-Accumulate Long (MULL, MLAL)</B><BR>Optionally supported, INCLUDED in 
ARMv3M, EXCLUDED in ARMv4xM/ARMv5xM.<BR>Restrictions: RdHi,RdLo,Rm must be 
different registers. R15 may not be used.<BR>Execution Time: 1S+(m+1)I for MULL, 
and 1S+(m+2)I for MLAL. Whereas 'm' depends on whether/how many most significant 
bits of Rs are "all zero" (UMULL/UMLAL) or "all zero or all one" (SMULL,SMLAL). 
That is m=1 for Bit 31-8, m=2 for Bit 31-16, m=3 for Bit 31-24, and m=4 
otherwise.<BR>Flags (if S=1): Z=zeroflag, N=signflag, C=destroyed (ARMv4 and 
below) or C=not affected (ARMv5 and up), V=destroyed??? (ARMv4 and below???) or 
V=not affected (ARMv5 and up).<BR><BR><B>Signed Halfword Multiply 
(SMLAxy,SMLAWy,SMLALxy,SMULxy,SMULWy)</B><BR>Supported by E variants of ARMv5 
and up, ie. ARMv5TE(xP).<BR>Q-flag gets set on 32bit SMLAxy/SMLAWy addition 
overflows, however, the result is NOT truncated (as it'd be done with QADD 
opcodes).<BR>Q-flag is NOT affected on (rare) 64bit SMLALxy addition 
overflows.<BR>SMULxy/SMULWy cannot overflow, and thus leave Q-flag unchanged as 
well.<BR>NZCV-flags are not affected by Halfword multiplies.<BR>Execution Time: 
1S+Interlock (SMULxy,SMLAxy,SMULWx,SMLAWx)<BR>Execution Time: 1S+1I+Interlock 
(SMLALxy)<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm9singledatatransferldrstrpld></A><FONT size=+2>&nbsp;ARM.9: 
      Single Data Transfer (LDR, STR, 
PLD)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (Must be 1111b for PLD)
  27-26  Must be 01b for this instruction
  25     I - Immediate Offset Flag (0=Immediate, 1=Shifted Register)
  24     P - Pre/Post (0=post; add offset after transfer, 1=pre; before trans.)
  23     U - Up/Down Bit (0=down; subtract offset from base, 1=up; add to base)
  22     B - Byte/Word bit (0=transfer word quantity, 1=transfer byte quantity)
  When above Bit 24 P=0 (Post-indexing, write-back is ALWAYS enabled):
    21     T - Memory Management (0=Normal, 1=Force non-privileged access)
  When above Bit 24 P=1 (Pre-indexing, write-back is optional):
    21     W - Write-back bit (0=no write-back, 1=write address into base)
  20     L - Load/Store bit (0=Store to memory, 1=Load from memory)
          0: STR{cond}{B}{T} Rd,&lt;Address&gt;   ;[Rn+/-&lt;offset&gt;]=Rd
          1: LDR{cond}{B}{T} Rd,&lt;Address&gt;   ;Rd=[Rn+/-&lt;offset&gt;]
         (1: PLD &lt;Address&gt; ;Prepare Cache for Load, see notes below)
          Whereas, B=Byte, T=Force User Mode (only for POST-Indexing)
  19-16  Rn - Base register               (R0..R15) (including R15=PC+8)
  15-12  Rd - Source/Destination Register (R0..R15) (including R15=PC+12)
  When above I=0 (Immediate as Offset)
    11-0   Unsigned 12bit Immediate Offset (0-4095, steps of 1)
  When above I=1 (Register shifted by Immediate as Offset)
    11-7   Is - Shift amount      (1-31, 0=Special/See below)
    6-5    Shift Type             (0=LSL, 1=LSR, 2=ASR, 3=ROR)
    4      Must be 0 (Reserved, see ARM.17, The Undefined Instruction)
    3-0    Rm - Offset Register   (R0..R14) (not including PC=R15)
</PRE></TD></TR></TBODY></TABLE><BR><B>Instruction Formats for 
&lt;Address&gt;</B><BR>An expression which generates an address:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  &lt;expression&gt;                  ;an immediate used as address
  ;*** restriction: must be located in range PC+/-4095+8, if so,
  ;*** assembler will calculate offset and use PC (R15) as base.
</PRE></TD></TR></TBODY></TABLE>Pre-indexed addressing specification:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [Rn]                          ;offset = zero
  [Rn, &lt;#{+/-}expression&gt;]{!}   ;offset = immediate
  [Rn, {+/-}Rm{,&lt;shift&gt;} ]{!}   ;offset = register shifted by immediate
</PRE></TD></TR></TBODY></TABLE>Post-indexed addressing specification:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [Rn], &lt;#{+/-}expression&gt;      ;offset = immediate
  [Rn], {+/-}Rm{,&lt;shift&gt;}       ;offset = register shifted by immediate
</PRE></TD></TR></TBODY></TABLE>Whereas...<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  &lt;shift&gt;  immediate shift such like LSL#4, ROR#2, etc. (see ARM.5).
  {!}      exclamation mark ("!") indicates write-back (Rn will be updated).
</PRE></TD></TR></TBODY></TABLE><BR><B>Notes</B><BR>Shift amount 0 has special 
meaning, as described in ARM.5 Data Processing.<BR>When writing a word (32bit) 
to memory, the address should be word-aligned.<BR>When reading a byte from 
memory, upper 24 bits of Rd are zero-extended.<BR>LDR PC,&lt;op&gt; on ARMv4 
leaves CPSR.T unchanged.<BR>LDR PC,&lt;op&gt; on ARMv5 sets CPSR.T to &lt;op&gt; 
Bit0, (1=Switch to Thumb).<BR><BR>When reading a word from a halfword-aligned 
address (which is located in the middle between two word-aligned addresses), the 
lower 16bit of Rd will contain [address] ie. the addressed halfword, and the 
upper 16bit of Rd will contain [Rd-2] ie. more or less unwanted garbage. 
However, by isolating lower bits this may be used to read a halfword from 
memory. (Above applies to little endian mode, as used in GBA.)<BR><BR>In a 
virtual memory based environment (ie. not in the GBA), aborts (ie. page faults) 
may take place during execution, if so, Rm and Rn should not specify the same 
register when post-indexing is used, as the abort-handler might have problems to 
reconstruct the original value of the register.<BR><BR>Return: CPSR flags are 
not affected.<BR>Execution Time: For normal LDR: 1S+1N+1I. For LDR PC: 2S+2N+1I. 
For STR: 2N.<BR><BR><B>PLD &lt;Address&gt; ;Prepare Cache for Load</B><BR>PLD 
must use following settings cond=1111b, P=1, B=1, W=0, L=1, Rd=1111b, the 
address may not use post-indexing, and may not use writeback, the opcode is 
encoded identical as LDRNVB R15,&lt;Address&gt;.<BR>PLD signalizes to the memory 
system that a specific memory address will be soon accessed, the memory system 
may use this hint to prepare caching/pipelining, aside from that, PLD does not 
have any affect to the program logic, and behaves identical as NOP.<BR>PLD 
supported by ARMv5TE only, not ARMv5, not ARMv5TExP.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm10halfworddoublewordandsigneddatatransfer></A><FONT 
      size=+2>&nbsp;ARM.10: Halfword, Doubleword, and Signed Data 
    Transfer</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-25  Must be 000b for this instruction
  24     P - Pre/Post (0=post; add offset after transfer, 1=pre; before trans.)
  23     U - Up/Down Bit (0=down; subtract offset from base, 1=up; add to base)
  22     I - Immediate Offset Flag (0=Register Offset, 1=Immediate Offset)
  When above Bit 24 P=0 (Post-indexing, write-back is ALWAYS enabled):
    21     Not used, must be zero (0)
  When above Bit 24 P=1 (Pre-indexing, write-back is optional):
    21     W - Write-back bit (0=no write-back, 1=write address into base)
  20     L - Load/Store bit (0=Store to memory, 1=Load from memory)
  19-16  Rn - Base register                (R0-R15) (Including R15=PC+8)
  15-12  Rd - Source/Destination Register  (R0-R15) (Including R15=PC+12)
  11-8   When above Bit 22 I=0 (Register as Offset):
           Not used. Must be 0000b
         When above Bit 22 I=1 (immediate as Offset):
           Immediate Offset (upper 4bits)
  7      Reserved, must be set (1)
  6-5    Opcode (0-3)
         When Bit 20 L=0 (Store) (and Doubleword Load/Store):
          0: Reserved for SWP instruction (see ARM.12 Single Data Swap)
          1: STR{cond}H  Rd,&lt;Address&gt;  ;Store halfword   [a]=Rd
          2: LDR{cond}D  Rd,&lt;Address&gt;  ;Load Doubleword  R(d)=[a], R(d+1)=[a+4]
          3: STR{cond}D  Rd,&lt;Address&gt;  ;Store Doubleword [a]=R(d), [a+4]=R(d+1)
         When Bit 20 L=1 (Load):
          0: Reserved.
          1: LDR{cond}H  Rd,&lt;Address&gt;  ;Load Unsigned halfword (zero-extended)
          2: LDR{cond}SB Rd,&lt;Address&gt;  ;Load Signed byte (sign extended)
          3: LDR{cond}SH Rd,&lt;Address&gt;  ;Load Signed halfword (sign extended)
  4      Reserved, must be set (1)
  3-0    When above Bit 22 I=0:
           Rm - Offset Register            (R0-R14) (not including R15)
         When above Bit 22 I=1:
           Immediate Offset (lower 4bits)  (0-255, together with upper bits)
</PRE></TD></TR></TBODY></TABLE>STRH,LDRH,LDRSB,LDRSH supported on ARMv4 and 
up.<BR>STRD/LDRD supported on ARMv5TE only, not ARMv5, not 
ARMv5TExP.<BR>STRD/LDRD: base writeback: Rn should not be same as R(d) or 
R(d+1).<BR>STRD: index register: Rm should not be same as R(d) or 
R(d+1).<BR>STRD/LDRD: Rd must be an even numbered register 
(R0,R2,R4,R6,R8,R10,R12).<BR>STRD/LDRD: Address must be double-word aligned 
(multiple of eight).<BR><BR><B>Instruction Formats for &lt;Address&gt;</B><BR>An 
expression which generates an address:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  &lt;expression&gt;                  ;an immediate used as address
  ;*** restriction: must be located in range PC+/-255+8, if so,
  ;*** assembler will calculate offset and use PC (R15) as base.
</PRE></TD></TR></TBODY></TABLE>Pre-indexed addressing specification:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [Rn]                          ;offset = zero
  [Rn, &lt;#{+/-}expression&gt;]{!}   ;offset = immediate
  [Rn, {+/-}Rm]{!}              ;offset = register
</PRE></TD></TR></TBODY></TABLE>Post-indexed addressing specification:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [Rn], &lt;#{+/-}expression&gt;      ;offset = immediate
  [Rn], {+/-}Rm                 ;offset = register
</PRE></TD></TR></TBODY></TABLE>Whereas...<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  {!}      exclamation mark ("!") indicates write-back (Rn will be updated).
</PRE></TD></TR></TBODY></TABLE><BR>Return: No Flags affected.<BR>Execution 
Time: For Normal LDR, 1S+1N+1I. For LDR PC, 2S+2N+1I. For STRH 2N.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm11blockdatatransferldmstm></A><FONT size=+2>&nbsp;ARM.11: 
      Block Data Transfer (LDM,STM)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-25  Must be 100b for this instruction
  24     P - Pre/Post (0=post; add offset after transfer, 1=pre; before trans.)
  23     U - Up/Down Bit (0=down; subtract offset from base, 1=up; add to base)
  22     S - PSR &amp; force user bit (0=No, 1=load PSR or force user mode)
  21     W - Write-back bit (0=no write-back, 1=write address into base)
  20     L - Load/Store bit (0=Store to memory, 1=Load from memory)
          0: STM{cond}{amod} Rn{!},&lt;Rlist&gt;{^}  ;Store (Push)
          1: LDM{cond}{amod} Rn{!},&lt;Rlist&gt;{^}  ;Load  (Pop)
          Whereas, {!}=Write-Back (W), and {^}=PSR/User Mode (S)
  19-16  Rn - Base register                (R0-R14) (not including R15)
  15-0   Rlist - Register List
  (Above 'offset' is meant to be the number of words specified in Rlist.)
</PRE></TD></TR></TBODY></TABLE><BR><B>Addressing Modes {amod}</B><BR>The 
IB,IA,DB,DA suffixes directly specify the desired U and P bits:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  IB  increment before          ;P=1, U=1
  IA  increment after           ;P=0, U=1
  DB  decrement before          ;P=1, U=0
  DA  decrement after           ;P=0, U=0
</PRE></TD></TR></TBODY></TABLE>Alternately, FD,ED,FA,EA could be used, mostly 
to simplify mnemonics for stack transfers.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ED  empty stack, descending   ;LDM: P=1, U=1  ;STM: P=0, U=0
  FD  full stack,  descending   ;     P=0, U=1  ;     P=1, U=0
  EA  empty stack, ascending    ;     P=1, U=0  ;     P=0, U=1
  FA  full stack,  ascending    ;     P=0, U=0  ;     P=1, U=1
</PRE></TD></TR></TBODY></TABLE>Ie. the following expressions are aliases for 
each other:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  STMFD=STMDB=PUSH   STMED=STMDA   STMFA=STMIB   STMEA=STMIA
  LDMFD=LDMIA=POP    LDMED=LDMIB   LDMFA=LDMDA   LDMEA=LDMDB
</PRE></TD></TR></TBODY></TABLE>Note: The equivalent THUMB functions use fixed 
organization:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  PUSH/POP: full descending     ;base register SP (R13)
  LDM/STM:  increment after     ;base register R0..R7
</PRE></TD></TR></TBODY></TABLE>Descending is common stack organization as used 
in 80x86 and Z80 CPUs, SP is decremented when pushing/storing data, and 
incremented when popping/loading data.<BR><BR><B>When S Bit is set 
(S=1)</B><BR>If instruction is LDM and R15 is in the list: (Mode Changes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  While R15 loaded, additionally: CPSR=SPSR_&lt;current mode&gt;
</PRE></TD></TR></TBODY></TABLE>Otherwise: (User bank transfer)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Rlist is referring to User Bank Registers, R0-R15 (rather than
  register related to the current mode, such like R14_svc etc.)
  Base write-back should not be used for User bank transfer.
  !  When instruction is LDM:                                   !
  !  If the following instruction reads from a banked register, !
  !  like R14_svc, then CPU might still read R14 instead. If    !
  !  necessary insert a dummy instruction such like MOV R0,R0.  !
</PRE></TD></TR></TBODY></TABLE><BR><B>Notes</B><BR>The lowest Register in Rlist 
(R0 if its in the list) will be loaded/stored to/from the lowest memory 
address.<BR>The base address should be usually word-aligned.<BR>LDM Rn,...,PC on 
ARMv4 leaves CPSR.T unchanged.<BR>LDR Rn,...,PC on ARMv5 sets CPSR.T to 
&lt;op&gt; Bit0, (1=Switch to Thumb).<BR><BR>Return: No Flags 
affected.<BR>Execution Time: For normal LDM, nS+1N+1I. For LDM PC, (n+1)S+2N+1I. 
For STM (n-1)S+2N. Where n is the number of words transferred.<BR><BR><B>Strange 
Effects on Invalid Rlist's</B><BR>Empty Rlist: R15 loaded/stored (ARMv4 only), 
and Rb=Rb+/-40h (ARMv4-v5).<BR>Writeback with Rb included in Rlist: Store OLD 
base if Rb is FIRST entry in Rlist, otherwise store NEW base (STM/ARMv4), always 
store OLD base (STM/ARMv5), no writeback (LDM/ARMv4), writeback if Rb is "the 
ONLY register, or NOT the LAST register" in Rlist (LDM/ARMv5).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm12singledataswapswp></A><FONT size=+2>&nbsp;ARM.12: Single 
      Data Swap (SWP)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-23  Must be 00010b for this instruction
         Opcode (fixed)
           SWP{cond}{B} Rd,Rm,[Rn]      ;Rd=[Rn], [Rn]=Rm
  22     B - Byte/Word bit (0=swap word quantity, 1=swap byte quantity)
  21-20  Must be 00b for this instruction
  19-16  Rn - Base register                     (R0-R14)
  15-12  Rd - Destination Register              (R0-R14)
  11-4   Must be 00001001b for this instruction
  3-0    Rm - Source Register                   (R0-R14)
</PRE></TD></TR></TBODY></TABLE>SWP/SWPB supported by ARMv2a and up.<BR>Swap 
works properly including if Rm and Rn specify the same register.<BR>R15 may not 
be used for either Rn,Rd,Rm. (Rn=R15 would be MRS opcode).<BR>Upper bits of Rd 
are zero-expanded when using Byte quantity. For info about byte and word data 
memory addressing, read LDR and STR opcode description.<BR>Execution Time: 
1S+2N+1I. That is, 2N data cycles, 1S code cycle, plus 1I.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm13softwareinterruptswibkpt></A><FONT size=+2>&nbsp;ARM.13: 
      Software Interrupt (SWI,BKPT)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (must be 1110b for BKPT, ie. Condition=always)
  27-24  Opcode
          1111b: SWI{cond} nn   ;software interrupt
          0001b: BKPT      nn   ;breakpoint (ARMv5 and up)
  For SWI:
   23-0   nn - Comment Field, ignored by processor (24bit value)
  For BKPT:
   23-20  Must be 0010b for BKPT
   19-8   nn - upper 12bits of comment field, ignored by processor
   7-4    Must be 0111b for BKPT
   3-0    nn - lower 4bits of comment field, ignored by processor
</PRE></TD></TR></TBODY></TABLE>SWI supposed for calls to the operating system - 
Enter Supervisor mode (SVC) in ARM state. BKPT intended for debugging - enters 
Abort mode in ARM state via Prefetch Abort vector.<BR><BR>Execution 
SWI/BKPT:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R14_svc=PC+4     R14_abt=PC+4   ;save return address
  SPSR_svc=CPSR    SPSR_abt=CPSR  ;save CPSR flags
  CPSR=&lt;changed&gt;   CPSR=&lt;changed&gt; ;Enter svc/abt, ARM state, IRQs disabled
  PC=VVVV0008h     PC=VVVV000Ch   ;jump to SWI/PrefetchAbort vector address
</PRE></TD></TR></TBODY></TABLE>Execution Time: 2S+1N<BR><BR>Interpreting the 
Comment Field:<BR>The immediate parameter is ignored by the processor, the user 
interrupt handler may read-out this number by examining the lower 24bit of the 
32bit opcode opcode at [R14_svc-4]. In case that your program executes SWI's 
from inside of THUMB mode also: Your SWI handler must then examine the T Bit 
SPSR_svc in order to determine whether it's been a THUMB SWI - if so, examining 
the lower 8bit of the 16bit opcode opcode at [R14_svc-2].<BR><BR>For Returning 
from SWI use this instruction:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MOVS PC,R14
</PRE></TD></TR></TBODY></TABLE>That instructions does both restoring PC and 
CPSR, ie. PC=R14_svc, and CPSR=SPRS_svc.<BR><BR>Nesting SWIs:<BR>SPSR_svc and 
R14_svc should be saved on stack before either invoking nested SWIs, or (if the 
IRQ handler uses SWIs) before enabling IRQs.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm14coprocessordataoperationscdp></A><FONT 
      size=+2>&nbsp;ARM.14: Coprocessor Data Operations 
  (CDP)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (or 1111b for CDP2 opcode on ARMv5 and up)
  27-24  Must be 1110b for this instruction
         ARM-Opcode (fixed)
           CDP{cond} Pn,&lt;cpopc&gt;,Cd,Cn,Cm{,&lt;cp&gt;}
           CDP2      Pn,&lt;cpopc&gt;,Cd,Cn,Cm{,&lt;cp&gt;}
  23-20  CP Opc - Coprocessor operation code       (0-15)
  19-16  Cn     - Coprocessor operand Register     (C0-C15)
  15-12  Cd     - Coprocessor destination Register (C0-C15)
  11-8   Pn     - Coprocessor number               (P0-P15)
  7-5    CP     - Coprocessor information          (0-7)
  4      Reserved, must be zero (otherwise MCR/MRC opcode)
  3-0    Cm     - Coprocessor operand Register     (C0-C15)
</PRE></TD></TR></TBODY></TABLE>CDP supported by ARMv2 and up, CDP2 by ARMv5 and 
up.<BR>Execution time: 1S+bI, b=number of cycles in coprocessor busy-wait 
loop.<BR>Return: No flags affected, no ARM-registers used/modified.<BR>For 
details refer to original ARM docs, irrelevant in GBA because no coprocessor 
exists.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm15coprocessordatatransfersldcstc></A><FONT 
      size=+2>&nbsp;ARM.15: Coprocessor Data Transfers 
  (LDC,STC)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (or 1111b for LDC2/STC2 opcodes on ARMv5 and up)
  27-25  Must be 110b for this instruction
  24     P - Pre/Post (0=post; add offset after transfer, 1=pre; before trans.)
  23     U - Up/Down Bit (0=down; subtract offset from base, 1=up; add to base)
  22     N - Transfer length (0-1, interpretation depends on co-processor)
  21     W - Write-back bit (0=no write-back, 1=write address into base)
  20     Opcode (0-1)
          0: STC{cond}{L} Pn,Cd,&lt;Address&gt;  ;Store to memory (from coprocessor)
          0: STC2{L}      Pn,Cd,&lt;Address&gt;  ;Store to memory (from coprocessor)
          1: LDC{cond}{L} Pn,Cd,&lt;Address&gt;  ;Read from memory (to coprocessor)
          1: LDC2{L}      Pn,Cd,&lt;Address&gt;  ;Read from memory (to coprocessor)
          whereas {L} indicates long transfer (Bit 22: N=1)
  19-16  Rn     - ARM Base Register              (R0-R15)     (R15=PC+8)
  15-12  Cd     - Coprocessor src/dest Register  (C0-C15)
  11-8   Pn     - Coprocessor number             (P0-P15)
  7-0    Offset - Unsigned Immediate, step 4     (0-1020, in steps of 4)
</PRE></TD></TR></TBODY></TABLE>LDC/STC supported by ARMv2 and up, LDC2/STC2 by 
ARMv5 and up.<BR>Execution time: (n-1)S+2N+bI, n=number of words 
transferred.<BR>For details refer to original ARM docs, irrelevant in GBA 
because no coprocessor exists.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm16coprocessorregistertransfersmrcmcr></A><FONT 
      size=+2>&nbsp;ARM.16: Coprocessor Register Transfers (MRC, 
  MCR)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition (or 1111b for MRC2/MCR2 opcodes on ARMv5 and up)
  27-24  Must be 1110b for this instruction
  23-21  CP Opc - Coprocessor operation code         (0-7)
  20     ARM-Opcode (0-1)
          0: MCR{cond} Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;}   ;move from ARM to CoPro
          0: MCR2      Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;}   ;move from ARM to CoPro
          1: MRC{cond} Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;}   ;move from CoPro to ARM
          1: MRC2      Pn,&lt;cpopc&gt;,Rd,Cn,Cm{,&lt;cp&gt;}   ;move from CoPro to ARM
  19-16  Cn     - Coprocessor source/dest. Register  (C0-C15)
  15-12  Rd     - ARM source/destination Register    (R0-R15)
  11-8   Pn     - Coprocessor number                 (P0-P15)
  7-5    CP     - Coprocessor information            (0-7)
  4      Reserved, must be one (1) (otherwise CDP opcode)
  3-0    Cm     - Coprocessor operand Register       (C0-C15)
</PRE></TD></TR></TBODY></TABLE>MCR/MRC supported by ARMv2 and up, MCR2/MRC2 by 
ARMv5 and up.<BR>A22i syntax allows to use MOV with Rd specified as first 
(dest), or last (source) operand. Native MCR/MRC syntax uses Rd as middle 
operand, &lt;cp&gt; can be ommited if &lt;cp&gt; is zero.<BR>When using MCR with 
R15: Coprocessor will receive a data value of PC+12.<BR>When using MRC with R15: 
Bit 31-28 of data are copied to Bit 31-28 of CPSR (ie. N,Z,C,V flags), other 
data bits are ignored, CPSR Bit 27-0 are not affected, R15 (PC) is not 
affected.<BR>Execution time: 1S+bI+1C for MCR, 1S+(b+1)I+1C for MRC.<BR>Return: 
For MRC only: Either R0-R14 modified, or flags affected (see above).<BR>For 
details refer to original ARM docs. The opcodes irrelevant for GBA/NDS7 because 
no coprocessor exists (except for a dummy CP14 unit). However, NDS9 includes a 
working CP15 unit.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp14icebreakerdebugcommunicationschannel">ARM 
CP14 ICEbreaker Debug Communications Channel</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armxcoprocessordoubleregistertransfermcrrmrrc></A><FONT 
      size=+2>&nbsp;ARM.X: Coprocessor Double-Register Transfer 
      (MCRR,MRRC)</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-21  Must be 1100010b for this instruction
  20     L - Opcode (Load/Store)
          0: MCRR{cond} Pn,opcode,Rd,Rn,Cm  ;write Rd,Rn to coproc
          1: MRRC{cond} Pn,opcode,Rd,Rn,Cm  ;read Rd,Rn from coproc
  19-16  Rn - Second source/dest register      (R0-R14)
  15-12  Rd - First source/dest register       (R0-R14)
  11-8   Pn     - Coprocessor number           (P0-P15)
  7-4    CP Opc - Coprocessor operation code   (0-15)
  3-0    Cm     - Coprocessor operand Register (C0-C15)
</PRE></TD></TR></TBODY></TABLE>Supported by ARMv5TE only, not ARMv5, not 
ARMv5TExP.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm17undefinedinstruction></A><FONT size=+2>&nbsp;ARM.17: 
      Undefined Instruction</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-25  Must be 011b for this instruction
  24-5   Reserved for future use
  4      Must be 1b for this instruction
  3-0    Reserved for future use
</PRE></TD></TR></TBODY></TABLE>No assembler mnemonic exists, following 
bitstreams are (not) reserved.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cond011xxxxxxxxxxxxxxxxxxxx1xxxx - reserved for future use (except below).
  cond01111111xxxxxxxxxxxx1111xxxx - free for user.
</PRE></TD></TR></TBODY></TABLE>Execution time: 2S+1I+1N.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armxcountleadingzeros></A><FONT size=+2>&nbsp;ARM.X: Count 
      Leading Zeros</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-16  Must be 0001.0110.1111b for this instruction
         Opcode (fixed)
           CLZ{cond} Rd,Rm  ;Rd=Number of leading zeros in Rm
  15-12  Rd - Destination Register              (R0-R14)
  11-4   Must be 1111.0001b for this instruction
  3-0    Rm - Source Register                   (R0-R14)
</PRE></TD></TR></TBODY></TABLE>CLZ supported by ARMv5 and up. Execution time: 
1S.<BR>Return: No Flags affected. Rd=0..32.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armxqaddqsub></A><FONT size=+2>&nbsp;ARM.X: 
  QADD/QSUB</FONT></TD></TR></TBODY></TABLE><BR><B>Opcode Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  31-28  Condition
  27-24  Must be 0001b for this instruction
  23-20  Opcode
          0000b: QADD{cond}  Rd,Rm,Rn    ;Rd=Rm+Rn
          0010b: QSUB{cond}  Rd,Rm,Rn    ;Rd=Rm-Rn
          0100b: QDADD{cond} Rd,Rm,Rn    ;Rd=Rm+Rn*2 (doubled)
          0110b: QDSUB{cond} Rd,Rm,Rn    ;Rd=Rm-Rn*2 (doubled)
  19-16  Rn - Second Source Register            (R0-R14)
  15-12  Rd - Destination Register              (R0-R14)
  11-4   Must be 00000101b for this instruction
  3-0    Rm - First Source Register             (R0-R14)
</PRE></TD></TR></TBODY></TABLE>Supported by E variants of ARMv5 and up, ie. 
ARMv5TE(xP).<BR>Execution time: 1S+Interlock.<BR>Results truncated to signed 
32bit range in case of overflows, with the Q-flag being set (and being left 
unchanged otherwise). NZCV flags are not affected.<BR>Note: Rn*2 is internally 
processed first, and may get truncated - even if the final result would fit into 
range.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=arm26bitmemoryinterface></A><FONT size=+2>&nbsp;ARM 26bit 
      Memory Interface</FONT></TD></TR></TBODY></TABLE><BR>The 26bit Memory Interface 
was used by ARMv1 and ARMv2. The 32bit interface is used by ARMv3 and newer, 
however, 26bit backward compatibility was included in all ARMv3 (except ARMv3G), 
and optionally in some non-T variants of ARMv4.<BR><BR><B>Format of R15 in 26bit 
Mode (Program Counter Register)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Name     Expl.
  31-28 N,Z,C,V  Flags (Sign, Zero, Carry, Overflow)
  27-26 I,F      Interrupt Disable bits (IRQ, FIQ) (1=Disable)
  25-2  PC       Program Counter, 24bit, Step 4 (64M range)
  1-0   M1,M0    Mode (0=User, 1=FIQ, 2=IRQ, 3=Supervisor)
</PRE></TD></TR></TBODY></TABLE>Branches with +/-32M range wrap the PC register, 
and can reach all 64M memory.<BR><BR><B>Reading from R15</B><BR>If R15 is 
specified in bit16-19 of an opcode, then NZCVIF and M0,1 are masked (zero), 
otherwise the full 32bits are used.<BR><BR><B>Writing to R15</B><BR>Data 
Processing opcodes with S=1, and LDM opcodes with PSR=1 can write to all 32bits 
in R15 (in 26bit mode, that is allowed even in user mode, though it does then 
affect only NZCF, not the write protected IFMM bits ???), other opcodes which 
write to R15 will modify only the program counter bits. Also, special 
CMP/CMN/TST/TEQ{P} opcodes can be used to write to the PSR bits in R15 without 
modifying the PC bits.<BR><BR><B>Exceptions</B><BR>SWIs, Reset, Data/Prefetch 
Aborts and Undefined instructions enter Supervisor mode. Interrupts enter IRQ 
and FIQ mode. Additionally, a special 26bit Address Exception exists, which 
enters Supervisor mode on accesses to memory addresses&gt;=64M as follows:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R14_svc = PC ($+8, including old PSR bits)
  M1,M0 = 11b = supervisor mode, F=same, I=1, PC=14h
</PRE></TD></TR></TBODY></TABLE>to continue at the fault location, return by 
SUBS PC,LR,8.<BR><BR><B>26bit Backwards Compatibility on 32bit ARMv3 and 
up</B><BR>CPSR M4=0 = 26bit mode (with USR,FIQ,IRQ,SVC modes in M1,M0)<BR>32bit 
CPUs with 26bit compatibility mode can be configured to switch into 32bit mode 
when encountering exceptions.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=pseudoinstructionsanddirectives></A><FONT size=+2>&nbsp;Pseudo 
      Instructions and Directives</FONT></TD></TR></TBODY></TABLE><BR><B>ARM Pseudo 
Instructions</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  nop              mov r0,r0
  ldr Rd,=Imm      ldr Rd,[r15,disp] ;use .pool as parameter field)
  add Rd,=addr     add/sub Rd,r15,disp
  adr Rd,addr      add/sub Rd,r15,disp
  adrl Rd,addr     two add/sub opcodes with disp=xx00h+00yyh
  mov Rd,Imm       mvn Rd,NOT Imm    ;or vice-versa
  and Rd,Rn,Imm    bic Rd,Rn,NOT Imm ;or vice-versa
  cmp Rd,Rn,Imm    cmn Rd,Rn,-Imm    ;or vice-versa
  add Rd,Rn,Imm    sub Rd,Rn,-Imm    ;or vice-versa
</PRE></TD></TR></TBODY></TABLE>All above opcodes may be made conditional by 
specifying a {cond} field.<BR><BR><B>THUMB Pseudo Instructions</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  nop              mov r8,r8
  ldr Rd,=Imm      ldr Rd,[r15,disp] ;use .pool as parameter field
  add Rd,=addr     add Rd,r15,disp
  adr Rd,addr      add Rd,r15,disp
  mov Rd,Rs        add Rd,Rs,0       ;with Rd,Rs in range r0-r7 each
</PRE></TD></TR></TBODY></TABLE><BR><B>A22i Directives</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  org  adr     assume following code from this address on
  .gba         indicate GBA program
  .nds         indicate NDS program
  .fix         fix GBA/NDS header checksum
  .ereader_create_bmp      create GBA e-Reader dotcode .BMP file(s) (bitmaps)
  .ereader_create_raw      create GBA e-Reader dotcode .RAW file (useless)
  .ereader_create_bin      create GBA e-Reader dotcode .BIN file (smallest)
  .ereader_japan_plus      japanese/plus     (default is non-japanese)
  .ereader_japan_original  japanese/original (with Z80-stub for GBA-code)
  .title 'Txt' defines a title (used for e-Reader dotcodes)
  .norewrite   do not delete existing output file (keep following data in file)
  .data?       following defines RAM data structure (assembled to nowhere)
  .code        following is normal ROM code/data (assembled to ROM image)
  .include     includes specified source code file (no nesting/error handling)
  .import      imports specified binary file (optional parameters: ,begin,len)
  .radix nn    changes default numeric format (nn=2,8,10,16 = bin/oct/dec/hex)
  .errif expr  generates an error message if expression is nonzero
  .if expr     assembles following code only if expression is nonzero
  .else        invert previous .if condition
  .endif       terminate .if/.ifdef/.ifndef
  .ifdef sym   assemble following only if symbol is defined
  .ifndef sym  assemble following only if symbol is not defined
  .align nn    aligns to an address divisible-by-nn, inserts 00's
  .msg         defines a no$gba debugmessage string, such like .msg 'Init Okay'
  .brk         defines a no$gba source code break opcode
  l equ n      l=n
  l:   [cmd]   l=$   (global label)
  @@l: [cmd]   @@l=$ (local label, all locals are reset at next global label)
  end          end of source code
  db ...       define 8bit data (bytes)
  dw ...       define 16bit data (halfwords)
  dd ...       define 32bit data (words)
  defs nn      define nn bytes space (zero-filled)
  ;...         defines a comment (ignored by the assembler)
  //           alias for CRLF, eg. allows &lt;db 'Text',0 // dw addr&gt; in one line
</PRE></TD></TR></TBODY></TABLE><BR><B>A22i Alias Directives (for compatibility 
with other assemblers)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  align        .align 4          code16    .thumb
  align nn     .align nn         .code 16  .thumb
  % nn         defs nn           code32    .arm
  .space nn    defs nn           .code 32  .arm
  ..ds nn      defs nn           ltorg     .pool
  x=n          x equ n           .ltorg    .pool
  .equ x,n     x equ n           ..ltorg   .pool
  .define x n  x equ n           dcb       db (8bit data)
  incbin       .import           defb      db (8bit data)
  @@@...       ;comment          .byte     db (8bit data)
  @ ...        ;comment          .ascii    db (8bit string)
  @*...        ;comment          dcw       dw (16bit data)
  @...         ;comment          defw      dw (16bit data)
  .text        .code             .hword    dw (16bit data)
  .bss         .data?            dcd       dd (32bit data)
  .global      (ignored)         defd      dd (32bit data)
  .extern      (ignored)         .long     dd (32bit data)
  .thumb_func  (ignored)         .word     dw/dd, don't use
  #directive   .directive        .end      end
  .fill nn,1,0 defs nn
</PRE></TD></TR></TBODY></TABLE><BR><B>Alias Conditions, Opcodes, 
Operands</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  hs   cs   ;condition higher or same = carry set
  asl  lsl  ;arithmetic shift left = logical shift left
</PRE></TD></TR></TBODY></TABLE><BR><B>A22i Numeric Formats &amp; 
Dialects</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Type          Normal       Alias
  Decimal       85           #85  &amp;d85
  Hexadecimal   55h          #55h  0x55  #0x55  $55  &amp;h55
  Octal         125o         0o125  &amp;o125
  Ascii         'U'          "U"
  Binary        01010101b    %01010101  0b01010101  &amp;b01010101
  Roman         &amp;rLXXXV      (very useful for arrays of kings and chapters)
</PRE></TD></TR></TBODY></TABLE>Note: The default numeric format can be changed 
by the .radix directive (usually 10=decimal). For example, with radix 16, values 
like "85" and "0101b" are treated as hexadecimal numbers (in that case, decimal 
and binary numbers can be still defined with prefixes &amp;d and 
&amp;b).<BR><BR><B>A22i Numeric Operators Priority</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Prio  Operator           Aliases
  8     (,) brackets
  7     +,- sign
  6     *,/,MOD,SHL,SHR    MUL,DIV,&lt;&lt;,&gt;&gt;
  5     +,- operation
  4     EQ,GE,GT,LE,LT,NE  =,&gt;=,&gt;,&lt;=,&lt;,&lt;&gt;,==,!=
  3     NOT
  2     AND
  1     OR,XOR             EOR
</PRE></TD></TR></TBODY></TABLE>Operators of same priority are processed from 
left to right.<BR>Boolean operators (priority 4) return 1=TRUE, 
0=FALSE.<BR><BR><B>A22i Nocash Syntax</B><BR>Even though A22i does recognize the 
official ARM syntax, it's also allowing to use friendly code:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  mov   r0,0ffh         ;no C64-style "#", and no C-style "0x" required
  stmia [r7]!,r0,r4-r5  ;square [base] brackets, no fancy {rlist} brackets
  mov   r0,cpsr         ;no confusing MSR and MRS (whatever which is which)
  mov   r0,p0,0,c0,c0,0 ;no confusing MCR and MRC (whatever which is which)
  ldr   r0,[score]      ;allows to use clean brackets for relative addresses
  push  rlist           ;alias for stmfd [r13]!,rlist (and same for pop/ldmfd)
  label:                ;label definitions recommended to use ":" colons
</PRE></TD></TR></TBODY></TABLE><BR>[A22i is the no$gba debug version's built-in 
source code assembler.]<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp14icebreakerdebugcommunicationschannel></A><FONT 
      size=+2>&nbsp;ARM CP14 ICEbreaker Debug Communications 
  Channel</FONT></TD></TR></TBODY></TABLE><BR>The ICEbreaker aka EmbeddedICE 
module may be found in ARM7TDMI and possibly also in other ARM processors. The 
main functionality of the module relies on external inputs (BREAKPT signal, 
etc.) being controlled by external debugging hardware. At software side, 
ICEbreaker contains a Debug Communications Channel (again to access external 
hardware), which can be accessed as coprocessor 14 via following opcodes:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MRC{cond} P14,0,Rd,C0,C0,0  ;Read Debug Comms Control Register
  MRC{cond} P14,0,Rd,C1,C0,0  ;Read Debug Comms Data Register
  MRC{cond} P14,0,Rd,C2,C0,0  ;Read Debug Comms Status Register
  MCR{cond} P14,0,Rd,C1,C0,0  ;Write Debug Comms Data Register
  MCR{cond} P14,0,Rd,C2,C0,0  ;Write Debug Comms Status Register
</PRE></TD></TR></TBODY></TABLE>The Control register consists of 
Bit31-28=ICEbreaker version (0001b for ARM7TDMI), Bit27-2=Not specified, 
Bit0/Bit1=Data Read/Write Status Flags.<BR><BR>The NDS7 and GBA allow to access 
CP14 (unlike as for CP0..CP13 &amp; CP15, access to CP14 doesn't generate any 
exceptions), however, the ICEbreaker module appears to be disabled (or 
completely unimplemented), any reads from P14,0,Rd,C0,C0,0 through 
P14,7,Rd,C15,C15,7 are simply returning the prefetched opcode value from [$+8]. 
ICEbreaker might be eventually used and enabled in Nintendo's hardware 
debuggers, although external breakpoints are reportedly implemented via /FIQ 
input rather than via ICEbreaker hardware.<BR>The NDS9 doesn't include a CP14 
unit (or it is fully disabled), any attempts to access it are causing invalid 
instruction exceptions.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15systemcontrolcoprocessor></A><FONT size=+2>&nbsp;ARM 
      CP15 System Control Coprocessor</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15overview">ARM CP15 
Overview</A><BR><A href="http://nocash.emubase.de/gbatek.htm#armcp15idcodes">ARM 
CP15 ID Codes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15controlregister">ARM CP15 
Control Register</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15memorymanagmentunitmmu">ARM 
CP15 Memory Managment Unit (MMU)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15protectionunitpu">ARM CP15 
Protection Unit (PU)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15cachecontrol">ARM CP15 Cache 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15tightlycoupledmemorytcm">ARM 
CP15 Tightly Coupled Memory (TCM)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15misc">ARM CP15 
Misc</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15overview></A><FONT size=+2>&nbsp;ARM CP15 
      Overview</FONT></TD></TR></TBODY></TABLE><BR><B>CP15</B><BR>In many ARM CPUs, 
particulary such with memory control facilities, coprocessor number 15 (CP15) is 
used as built-in System Control Coprocessor.<BR>CPUs without memory control 
functions typically do include a CP15 at all, in that case even an attempt to 
read the Main ID register will cause an Undefined Instruction 
exception.<BR><BR><B>CP15 Opcodes</B><BR>CP15 can be accessed via MCR and MRC 
opcodes, with Pn=P15, and &lt;cpopc&gt;=0.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  MCR{cond} P15,0,Rd,Cn,Cm,&lt;cp&gt;   ;move from ARM to CP15
  MRC{cond} P15,0,Rd,Cn,Cm,&lt;cp&gt;   ;move from CP15 to ARM
</PRE></TD></TR></TBODY></TABLE>Rd can be any ARM register in range R0-R14, R15 
should not be used with P15.<BR>Cn,Cm,&lt;cp&gt; are used to select a CP15 
register, eg. C0,C0,0 = Main ID Register.<BR>Other coprocessor opcodes (CDP, 
LDC, STC) cannot be used with P15.<BR><BR><B>CP15 Register List</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Register     Expl.
  C0,C0,0      Main ID Register (R)
  C0,C0,1      Cache Type and Size (R)
  C0,C0,2      TCM Physical Size (R)
  C1,C0,0      Control Register (R/W, or R=Fixed)
  C2,C0,0      PU Cachability Bits for Data/Unified Protection Region
  C2,C0,1      PU Cachability Bits for Instruction Protection Region
  C3,C0,0      PU Write-Bufferability Bits for Data Protection Regions
  C5,C0,0      PU Access Permission Data/Unified Protection Region
  C5,C0,1      PU Access Permission Instruction Protection Region
  C5,C0,2      PU Extended Access Permission Data/Unified Protection Region
  C5,C0,3      PU Extended Access Permission Instruction Protection Region
  C6,C0..C7,0  PU Protection Unit Data/Unified Region 0..7
  C6,C0..C7,1  PU Protection Unit Instruction Region 0..7
  C7,Cm,Op2    Cache Commands and Halt Function (W)
  C9,C0,0      Cache Data Lockdown
  C9,C0,1      Cache Instruction Lockdown
  C9,C1,0      TCM Data TCM Base and Virtual Size
  C9,C1,1      TCM Instruction TCM Base and Virtual Size
  C13,Cm,Op2   Misc Process ID registers
  C15,Cm,Op2   Misc Implementation Defined and Test/Debug registers
</PRE></TD></TR></TBODY></TABLE><BR><B>Data/Unified Registers</B><BR>Some 
Cache/PU/TCM registers are declared as "Data/Unified".<BR>That registers are 
used for Data accesses in case that the CPU contains separate Data and 
Instruction registers, otherwise the registers are used for both (unified) Data 
and Instruction accesses.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15idcodes></A><FONT size=+2>&nbsp;ARM CP15 ID 
    Codes</FONT></TD></TR></TBODY></TABLE><BR><B>C0,C0,0 - Main ID Register 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  12-15 ARM Era (0=Pre-ARM7, 7=ARM7, other=Post-ARM7)
</PRE></TD></TR></TBODY></TABLE>Post-ARM7 Processors<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Revision Number
  4-15  Primary Part Number (Bit12-15 must be other than 0 or 7)
        (eg. 946h for ARM946)
  16-19 Architecture        (1=v4, 2=v4T, 3=v5, 4=v5T, 5=v5TE)
  20-23 Variant Number
  24-31 Implementor         (41h=ARM, 44h=Digital Equipment Corp, 69h=Intel)
</PRE></TD></TR></TBODY></TABLE>ARM7 Processors<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Revision Number
  4-15  Primary Part Number (Bit12-15 must be 7)
  16-22 Variant Number
  23    Architecture        (0=v3, 1=v4T)
  24-31 Implementor         (41h=ARM, 44h=Digital Equipment Corp, 69h=Intel)
</PRE></TD></TR></TBODY></TABLE>Pre-ARM7 Processors<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Revision Number
  4-11  Processor ID LSBs (30h=ARM3/v2, 60h,61h,62=ARM600,610,620/v3)
  12-31 Processor ID MSBs (fixed, 41560h)
</PRE></TD></TR></TBODY></TABLE>Note: On the NDS9, this register is 41059461h. 
NDS7 and GBA don't have CP15s.<BR><BR><B>C0,C0,1 - Cache Type Register 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Instruction Cache (bits 0-1=len, 2=m, 3-5=assoc, 6-8=size, 9-11=zero)
  12-23 Data Cache        (bits 0-1=len, 2=m, 3-5=assoc, 6-8=size, 9-11=zero)
  24    Separate Cache Flag (0=Unified, 1=Separate Data/Instruction Caches)
  25-28 Cache Type (0,1,2,6,7=see below, other=reserved)
         Type Method         Cache cleaning         Cache lock-down
         0    Write-through  Not needed             Not supported
         1    Write-back     Read data block        Not supported
         2    Write-back     Register 7 operations  Not supported
         6    Write-back     Register 7 operations  Format A
         7    Write-back     Register 7 operations  Format B
  29-31 Reserved (zero)
</PRE></TD></TR></TBODY></TABLE>The 12bit Instruction/Data values are decoded as 
shown below,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Cache Absent  = (ASSOC=0 and M=1)       ;in that case overriding below
  Cache Size    = 200h+(100h*M) shl SIZE  ;min 0.5Kbytes, max 96Kbytes
  Associativity = (1+(0.5*M)) shl ASSOC   ;min 1-way,     max 192-way
  Line Length   = 8 shl LEN               ;min 8 bytes,   max 64 bytes
</PRE></TD></TR></TBODY></TABLE>For Unified cache (Bit 24=0), Instruction and 
Data values are identical.<BR><BR><B>C0,C0,2 - Tightly Coupled Memory (TCM) Size 
Register (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Reserved    (0)
  2     ITCM Absent (0=Present, 1=Absent)
  3-5   Reserved    (0)
  6-9   ITCM Size   (Size = 512 SHL N) (or 0=None)
  10-13 Reserved    (0)
  14    DTCM Absent (0=Present, 1=Absent)
  15-17 Reserved    (0)
  18-21 DTCM Size   (Size = 512 SHL N) (or 0=None)
  22-31 Reserved    (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>C0,C0,3..7 - Reserved 
(R)</B><BR>Unused/Reserved registers, containing the same value as 
C0,C0,0.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15controlregister></A><FONT size=+2>&nbsp;ARM CP15 
      Control Register</FONT></TD></TR></TBODY></TABLE><BR><B>C1,C0,0 - Control 
Register (R/W, or R=Fixed)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  MMU/PU Enable         (0=Disable, 1=Enable) (Fixed 0 if none)
  1  Alignment Fault Check (0=Disable, 1=Enable) (Fixed 0/1 if none/always on)
  2  Data/Unified Cache    (0=Disable, 1=Enable) (Fixed 0/1 if none/always on)
  3  Write Buffer          (0=Disable, 1=Enable) (Fixed 0/1 if none/always on)
  4  Exception Handling    (0=26bit, 1=32bit)    (Fixed 1 if always 32bit)
  5  26bit-address faults  (0=Enable, 1=Disable) (Fixed 1 if always 32bit)
  6  Abort Model (pre v4)  (0=Early, 1=Late Abort) (Fixed 1 if ARMv4 and up)
  7  Endian                (0=Little, 1=Big)     (Fixed 0/1 if fixed)
  8  System Protection bit (MMU-only)
  9  ROM Protection bit    (MMU-only)
  10 Implementation defined
  11 Branch Prediction     (0=Disable, 1=Enable)
  12 Instruction Cache     (0=Disable, 1=Enable) (ignored if Unified cache)
  13 Exception Vectors     (0=00000000h, 1=FFFF0000h)
  14 Cache Replacement     (0=Normal/PseudoRandom, 1=Predictable/RoundRobin)
  15 Pre-ARMv5 Mode        (0=Normal, 1=Pre ARMv5; LDM/LDR/POP_PC.Bit0/Thumb)
  16 DTCM Enable           (0=Disable, 1=Enable)
  17 DTCM Load Mode        (0=R/W, 1=DTCM Write-only)
  18 ITCM Enable           (0=Disable, 1=Enable)
  19 ITCM Load Mode        (0=R/W, 1=ITCM Write-only)
  20-31 Reserved           (keep these bits unchanged) (usually zero)
</PRE></TD></TR></TBODY></TABLE>Various bits in this register may be read-only 
(fixed 0 if unsupported, or fixed 1 if always activated).<BR>On the NDS 
bit0,2,7,12..19 are R/W, Bit3..6 are always set, all other bits are always 
zero.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15memorymanagmentunitmmu></A><FONT size=+2>&nbsp;ARM CP15 
      Memory Managment Unit (MMU)</FONT></TD></TR></TBODY></TABLE><BR>Function of some 
registers depends on whether the CPU contains a MMU or PU.<BR>MMU handles 
virtual addressing tables.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  C2,Cm,Op2  MMU Translation Table Base
  C3,Cm,Op2  MMU Domain Access Control
  C5,Cm,Op2  MMU Fault Status
  C6,Cm,Op2  MMU Fault Address
  C8,Cm,Op2  MMU TLB Control
  C10,Cm,Op2 MMU TLB Lockdown
</PRE></TD></TR></TBODY></TABLE>The GBA, and Nintendo DS do not have a 
MMU.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15protectionunitpu></A><FONT size=+2>&nbsp;ARM CP15 
      Protection Unit (PU)</FONT></TD></TR></TBODY></TABLE><BR>Protection Unit can be 
enabled in Bit0 of C1,C0,0 (Control Register).<BR><BR><B>C2,C0,0 - Cachability 
Bits for Data/Unified Protection Region (R/W)</B><BR><B>C2,C0,1 - Cachability 
Bits for Instruction Protection Region (if any) (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7  Cachable (C) bits for region 0-7
  8-31 Reserved/zero
</PRE></TD></TR></TBODY></TABLE><BR><B>C3,C0,0 - Write-Bufferability Bits for 
Data Protection Regions (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7  Bufferable (B) bits for region 0-7
  8-31 Reserved/zero
</PRE></TD></TR></TBODY></TABLE>Instruction fetches are, obviously, always 
read-operations. So, there are no write-bufferability bits for Instruction 
Protection Regions.<BR><BR><B>C5,C0,0 - Access Permission Data/Unified 
Protection Region (R/W)</B><BR><B>C5,C0,1 - Access Permission Instruction 
Protection Region (if any) (R/W)</B><BR><B>C5,C0,2 - Extended Access Permission 
Data/Unified Protection Region (R/W)</B><BR><B>C5,C0,3 - Extended Access 
Permission Instruction Protection Region (if any) (R/W/W)</B><BR>For C5,C0,0 and 
C5,C0,1:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Access Permission (AP) bits for region 0-7 (Bits 0-1=AP0, 2-3=AP1, etc)
  16-31 Reserved/zero
</PRE></TD></TR></TBODY></TABLE>For C5,C0,2 and C5,C0,3 (Extended):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-31  Access Permission (AP) bits for region 0-7 (Bits 0-3=AP0, 4-7=AP1, etc)
</PRE></TD></TR></TBODY></TABLE>The possible AP settings (0-3 for C5,C0,0..1, or 
0-15 for C5,C0,2..3) are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  AP  Privileged User
  0   -          -
  1   R/W        -
  2   R/W        R
  3   R/W        R/W
  5   R          -
  6   R          R
</PRE></TD></TR></TBODY></TABLE>Settings 5,6 only for Extended Registers, 
settings 4,7..15 are Reserved.<BR><BR><B>C6,C0..C7,0 - Protection Unit 
Data/Unified Region 0..7 (R/W)</B><BR><B>C6,C0..C7,1 - Protection Unit 
Instruction Region 0..7 (R/W) if any</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Protection Region Enable (0=Disable, 1=Enable)
  1-5   Protection Region Size   (2 SHL X) ;min=(X=11)=4KB, max=(X=31)=4GB
  6-11  Reserved/zero
  12-31 Protection Region Base address (Addr = Y*4K; must be SIZE-aligned)
</PRE></TD></TR></TBODY></TABLE>Overlapping Regions are allowed, Region 7 is 
having highest priority, region 0 lowest priority.<BR><BR><B>Background 
Region</B><BR>Additionally, any memory areas outside of the eight Protection 
Regions are handled as Background Region, this region has neither Read nor Write 
access.<BR><BR><B>Unified Region Note</B><BR>On the NDS, the Region registers 
are unified (C6,C0..C7,1 are read/write-able mirrors of C6,C0..C7,0). 
Netherless, the Cachabilty and Permission registers are NOT unified (separate 
registers exists for code and data settings).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15cachecontrol></A><FONT size=+2>&nbsp;ARM CP15 Cache 
      Control</FONT></TD></TR></TBODY></TABLE><BR>Cache enabled/controlled by Bit 
2,3,12,14 in Control Register.<BR>Cache type detected in Cache Type 
Register.<BR><BR><B>C7,C0..C15,0..7 - Cache Commands (W)</B><BR>Write-only Cache 
Command Register. Cm,Op2 operands used to select a specific command, with 
parameter value in Rd.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Cn,Cm,Op2 Rd   ARM9 Command
  C7,C0,4   0    Yes  Wait For Interrupt (Halt)
  C7,C5,0   0    Yes  Invalidate Entire Instruction Cache
  C7,C5,1   VA   Yes  Invalidate Instruction Cache Line
  C7,C5,2   S/I  -    Invalidate Instruction Cache Line
  C7,C5,4   0    -    Flush Prefetch Buffer
  C7,C5,6   0    -    Flush Entire Branch Target Cache
  C7,C5,7   IMP? -    Flush Branch Target Cache Entry
  C7,C6,0   0    Yes  Invalidate Entire Data Cache
  C7,C6,1   VA   Yes  Invalidate Data Cache Line
  C7,C6,2   S/I  -    Invalidate Data Cache Line
  C7,C7,0   0    -    Invalidate Entire Unified Cache
  C7,C7,1   VA   -    Invalidate Unified Cache Line
  C7,C7,2   S/I  -    Invalidate Unified Cache Line
  C7,C8,2   0    Yes  Wait For Interrupt (Halt), alternately to C7,C0,4
  C7,C10,1  VA   Yes  Clean Data Cache Line
  C7,C10,2  S/I  Yes  Clean Data Cache Line
  C7,C10,4  0    -    Drain Write Buffer
  C7,C11,1  VA   -    Clean Unified Cache Line
  C7,C11,2  S/I  -    Clean Unified Cache Line
  C7,C13,1  VA   Yes  Prefetch Instruction Cache Line
  C7,C14,1  VA   Yes  Clean and Invalidate Data Cache Line
  C7,C14,2  S/I  Yes  Clean and Invalidate Data Cache Line
  C7,C15,1  VA   -    Clean and Invalidate Unified Cache Line
  C7,C15,2  S/I  -    Clean and Invalidate Unified Cache Line
</PRE></TD></TR></TBODY></TABLE>Parameter values (Rd) formats:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0    Not used, should be zero
  VA   Virtual Address
  S/I  Set/index; Bit 31..(32-A) = Index, Bit (L+S-1)..L = Set ?
</PRE></TD></TR></TBODY></TABLE><BR><B>C9,C0,0 - Data Cache 
Lockdown</B><BR><B>C9,C0,1 - Instruction Cache Lockdown</B><BR>(Width (W) of 
index field depends on cache ASSOCIATIVETY.)<BR>Format A:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0..(31-W)  Reserved/zero
  (32-W)..31 Lockdown Block Index
</PRE></TD></TR></TBODY></TABLE>Format B:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0..(W-1)   Lockdown Block Index
  W..30      Reserved/zero
  31         L
</PRE></TD></TR></TBODY></TABLE><BR>Cache/Write-buffer should not be enabled for 
the whole 4GB memory area, high-speed TCM memory doesn't require caching, and 
caching would have fatal results on I/O ports. So, cache can be used only in 
combination with the Protection Unit, which allows to enable/disable caching in 
specified regions.<BR><BR><B>Note</B><BR>ARMv5 instruction set supports a Cache 
Prepare for Load opcode (PLD), see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#arm9singledatatransferldrstrpld">ARM.9: 
Single Data Transfer (LDR, STR, PLD)</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15tightlycoupledmemorytcm></A><FONT size=+2>&nbsp;ARM 
      CP15 Tightly Coupled Memory (TCM)</FONT></TD></TR></TBODY></TABLE><BR>TCM is 
high-speed memory, directly contained in the ARM CPU core.<BR><BR><B>TCM and 
DMA</B><BR>TCM doesn't use the ARM bus. A minor disadvantage is that TCM cannot 
be accessed by DMA. However, the main advantage is that, when using TCM, the CPU 
can be kept running without any waitstates even while the bus is used for DMA 
transfers. Operation during DMA works only if all code/data is located in TCM, 
waitstates are generated if any code/data outside TCM is accessed; in worst case 
(if there are no gaps in the DMA) then the CPU is halted until the DMA 
finishes.<BR><BR><B>TCM and DMA and IRQ</B><BR>No idea if/how IRQs are handled 
during DMA? Eventually (unlikely) code in TCM is kept executed until DMA 
finishes (ie. until the IRQ vector can be accessed. Eventually the IRQ vector is 
instantly accessed (causing to halt the CPU until DMA finishes). In both cases: 
Assuming that IRQs are enabled, and that the IRQ vector and/or IRQ handler are 
located outside TCM.<BR><BR><B>Separate Instruction (ITCM) and Data (DTCM) 
Memory</B><BR>DTCM can be used only for Data accesses, typically used for stacks 
and other frequently accessed data.<BR>ITCM is primarily intended for 
instruction accesses, but it can be also used for Data accesses (among others 
allowing to copy code to ITCM), however, performance isn't optimal when 
simultaneously accessing ITCM for code and data (such like opcodes in ITCM that 
use literal pool values in ITCM).<BR><BR><B>TCM Enable, TCM Load 
Mode</B><BR>CP15 Control Register allows to enable ITCM and DTCM, and to switch 
ITCM/DTCM into Load Mode. In Load Mode (when TCM is enabled), TCM becomes 
write-only; this allows to read data from source addresses in main memory, and 
to write data to destination addresses in TCM by using the same addresses; 
useful for initializing TCM with overlapping source/dest addresses; Load mode 
works with all Load/Store opcodes, it does NOT work with SWP/SWPB 
opcodes.<BR><BR>TCM Physical Size can be detected in 3rd ID Code Register. 
(C0,C0,2)<BR><BR><B>C9,C1,0 - Data TCM Size/Base (R/W)</B><BR><B>C9,C1,1 - 
Instruction TCM Size/Base (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Reserved     (0)
  1-5   Virtual Size (Size = 512 SHL N) ;min=(N=3)=4KB, max=(N=23)=4GB
  6-11  Reserved     (0)
  12-31 Region Base  (Base = X SHL 12)  ;Base must be Size-aligned
</PRE></TD></TR></TBODY></TABLE>The Virtual size settings should be normally 
same as the Physical sizes (see C0,C0,2). However, smaller sizes are allowed 
(using only the 1st some KB), as well as bigger sizes (TCM area is then filled 
with mirrors of physical TCM).<BR>The ITCM region base may be fixed (read-only), 
for example, on the NDS, ITCM base is always 00000000h, nethertheless the 
virtual size may be changed (allowing to mirror ITCM to higher addresses).<BR>If 
DTCM and ITCM do overlap, then ITCM appears to have priority.<BR><BR><B>TCM and 
PU</B><BR>TCM can be used without Protection Unit.<BR>When the protection unit 
is enabled, TCM is controlled by the PU just like normal memory, the PU should 
provide R/W Access Permission for TCM regions; cache and write-buffer are not 
required for high-speed TCM (so both should be disabled for TCM 
regions).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=armcp15misc></A><FONT size=+2>&nbsp;ARM CP15 
  Misc</FONT></TD></TR></TBODY></TABLE><BR><B>C13,C0,0 - Process ID for Fast 
Context Switch Extension (FCSE) (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-24  Reserved/zero
  25-31 Process ID (PID) (0-127) (0=Disable)
</PRE></TD></TR></TBODY></TABLE>The FCSE allows different processes (each 
assembled with ORG 0) to be located at virtual addresses in the 1st 32MB area. 
The FCSE splits the total 4GB address space into blocks of 32MB, accesses to 
Block(0) are redirected to Block(PID):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  IF addr&lt;32M then addr=addr+PID*32M
  Respectively, with PID=0, the address remains unchanged (FCSE disabled).
</PRE></TD></TR></TBODY></TABLE>The CPU-to-Memory address handling is shown 
below:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1. CPU outputs a virtual address (VA)
  2. FCSE adjusts the VA to a modified virtual address (MVA)
  3. Cache hits determined by examining the MVA, continue below if no hit
  4. MMU translates MVA to physical address (PA) (if no MMU present: PA=MVA)
  5. Memory access occurs at PA
</PRE></TD></TR></TBODY></TABLE>The FCSE allows limited virtual addressing even 
if no MMU is present.<BR>If the MMU is present, then either the FCSE and/or the 
MMU can be used for virtual addressing; the advantage of using the FCSE (a 
single write to C13,C0,0) is less overload; using the MMU for the same purpose 
would require to change virtual address translation table in memory, and to 
flush the cache.<BR>The NDS doesn't have a FCSE (the FCSE register is read-only, 
always zero).<BR><BR><B>C13,C0,1 - Trace Process ID (R/W)</B><BR><B>C13,C1,1 - 
Trace Process ID (Mirror) (R/W)</B><BR>This value is output to ETMPROCID pins 
(if any), allowing to notify external hardware about the currently executed 
process within multi-tasking programs.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-31  Process ID
</PRE></TD></TR></TBODY></TABLE>C13,C1,1 is a mirror of C13,C0,1 (for 
compatibility with other ARM processors).<BR>Both registers are read/write-able 
on NDS9, but there are no external 
pin-outs.<BR><BR><B>&lt;cpopc&gt;</B><BR>Unlike for all other CP15 registers, 
the &lt;cpopc&gt; operand of the MRC/MCR opcodes isn't always zero for below 
registers, so below registers are using "cpopc,Cn,Cm,op2" notation (instead of 
the normal "Cn,Cm,op2" notation).<BR><BR><B>Built-In-Self-Test 
(BIST)</B><BR>Allows to test internal memory (ie. TCM, Cache Memory, and Cache 
TAGs). The tests are filling (and verifying) the selected memory region thrice 
(once with the fillvalue, then with the inverted fillvalue, and then again with 
the fillvalue). The BIST functions are intended for diagnostics purposes only, 
not for use in normal program code (ARM doesn't guarantee future processors to 
have backwards compatible BIST functions).<BR><BR><B>0,C15,C0,1 - BIST TAG 
Control Register (R/W)</B><BR><B>1,C15,C0,1 - BIST TCM Control Register 
(R/W)</B><BR><B>2,C15,C0,1 - BIST Cache Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Data Control (see below)
  16-31 Instruction Control (see below)
</PRE></TD></TR></TBODY></TABLE>The above 16bit control values are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Start bit     (Write: 1=Start) (Read: 1=Busy)
  1     Pause bit     (1=Pause)
  2     Enable bit    (1=Enable)
  3     Fail Flag     (1=Error) (Read Only)
  4     Complete Flag (1=Ready) (Read Only)
  5-15  Size (2^(N+2) bytes) (min=N=1=8bytes, max=N=24=64MB)
</PRE></TD></TR></TBODY></TABLE>Size and Pause are not supported in all 
implementations.<BR>Caution: While and as long as the Enable bit is set, the 
corresponding memory region(s) will be disabled. Eg. when testing &lt;either&gt; 
DTCM &lt;and/or&gt; ITCM, &lt;both&gt; DTCM &lt;and&gt; ITCM are forcefully 
disabled in C1,C0,0 (Control Register), after the test the software must first 
clear the BIST enable bit, and then restore DTCM/ITCM bits in C1,C0,0. And of 
course, the content of the tested memory region must be restored when 
needed.<BR><BR><B>0,C15,C0,2 - BIST Instruction TAG Address 
(R/W)</B><BR><B>1,C15,C0,2 - BIST Instruction TCM Address 
(R/W)</B><BR><B>2,C15,C0,2 - BIST Instruction Cache Address 
(R/W)</B><BR><B>0,C15,C0,6 - BIST Data TAG Address (R/W)</B><BR><B>1,C15,C0,6 - 
BIST Data TCM Address (R/W)</B><BR><B>2,C15,C0,6 - BIST Data Cache Address 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-31  Word-aligned Destination Address within Memory Block (eg. within ITCM)
</PRE></TD></TR></TBODY></TABLE>On the NDS9, bit0-1, and bit21-31 are always 
zero.<BR><BR><B>0,C15,C0,3 - BIST Instruction TAG Fillvalue 
(R/W)</B><BR><B>1,C15,C0,3 - BIST Instruction TCM Fillvalue 
(R/W)</B><BR><B>2,C15,C0,3 - BIST Instruction Cache Fillvalue 
(R/W)</B><BR><B>0,C15,C0,7 - BIST Data TAG Fillvalue (R/W)</B><BR><B>1,C15,C0,7 
- BIST Data TCM Fillvalue (R/W)</B><BR><B>2,C15,C0,7 - BIST Data Cache Fillvalue 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-31  Fillvalue for BIST
</PRE></TD></TR></TBODY></TABLE>After BIST, the selected memory region is filled 
by that value. That is, on the NDS9 at least, all words will be filled with the 
SAME value (ie. NOT with increasing or randomly generated 
numbers).<BR><BR><B>0,C15,C0,0 - Cache Debug Test State Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-8    Reserved (zero)
  9      Disable Instruction Cache Linefill
  10     Disable Data Cache Linefill
  11     Disable Instruction Cache Streaming
  12     Disable Data Cache Streaming
  13-31  Reserved (zero/unpredictable)
</PRE></TD></TR></TBODY></TABLE><BR><B>3,C15,C0,0 - Cache Debug Index Register 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0..1    Reserved (zero)
  2..4    Word Address
  5..N    Index
  N+1..29 Reserved (zero)
  30..31  Segment
</PRE></TD></TR></TBODY></TABLE><BR><B>3,C15,C0,1 - Cache Debug Instruction TAG 
(R/W)</B><BR><B>3,C15,C0,2 - Cache Debug Data TAG (R/W)</B><BR><B>3,C15,C0,3 - 
Cache Debug Instruction Cache (R/W)</B><BR><B>3,C15,C0,4 - Cache Debug Data 
Cache (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0..1    Set
  2..3    Dirty Bits
  4       Valid
  5..N    Index
  N+1..31 TAG Address
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuinstructioncycletimes></A><FONT size=+2>&nbsp;CPU 
      Instruction Cycle Times</FONT></TD></TR></TBODY></TABLE><BR>Instruction Cycle 
Summary<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Instruction      Cycles      Additional</B>
  ---------------------------------------------------------------------
  Data Processing  1S          +1S+1N if R15 loaded, +1I if SHIFT(Rs)
  MSR,MRS          1S
  LDR              1S+1N+1I    +1S+1N if R15 loaded
  STR              2N
  LDM              nS+1N+1I    +1S+1N if R15 loaded
  STM              (n-1)S+2N
  SWP              1S+2N+1I
  BL (THUMB)       3S+1N
  B,BL             2S+1N
  SWI,trap         2S+1N
  MUL              1S+ml
  MLA              1S+(m+1)I
  MULL             1S+(m+1)I
  MLAL             1S+(m+2)I
  CDP              1S+bI
  LDC,STC          (n-1)S+2N+bI
  MCR              1N+bI+1C
  MRC              1S+(b+1)I+1C
  {cond} false     1S
</PRE></TD></TR></TBODY></TABLE><BR><BR>ARM9:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Q{D}ADD/SUB      1S+Interlock.
  CLZ              1S.
  LDR              1S+1N+1L
  LDRB,LDRH,LDRmis 1S+1N+2L
  LDR PC ...
  STR              1S+1N        (not 2N, and both in parallel)
</PRE></TD></TR></TBODY></TABLE>Execution Time: 1S+Interlock 
(SMULxy,SMLAxy,SMULWx,SMLAWx)<BR>Execution Time: 1S+1I+Interlock 
(SMLALxy)<BR><BR><BR>Whereas,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  n = number of words transferred
  b = number of cycles spent in coprocessor busy-wait loop
  m = depends on most significant byte(s) of multiplier operand
</PRE></TD></TR></TBODY></TABLE>Above 'trap' is meant to be the execution time 
for exceptions. And '{cond} false' is meant to be the execution time for 
conditional instructions which haven't been actually executed because the 
condition has been false.<BR><BR>The separate meaning of the N,S,I,C cycles 
is:<BR><BR><B>N - Non-sequential cycle</B><BR>Requests a transfer to/from an 
address which is NOT related to the address used in the previous cycle. (Called 
1st Access in GBA language).<BR>The execution time for 1N is 1 clock cycle (plus 
non-sequential access waitstates).<BR><BR><B>S - Sequential 
cycle</B><BR>Requests a transfer to/from an address which is located directly 
after the address used in the previous cycle. Ie. for 16bit or 32bit accesses at 
incrementing addresses, the first access is Non-sequential, the following 
accesses are sequential. (Called 2nd Access in GBA language).<BR>The execution 
time for 1S is 1 clock cycle (plus sequential access waitstates).<BR><BR><B>I - 
Internal Cycle</B><BR>CPU is just too busy, not even requesting a memory 
transfer for now.<BR>The execution time for 1I is 1 clock cycle (without any 
waitstates).<BR><BR><B>C - Coprocessor Cycle</B><BR>The CPU uses the data bus to 
communicate with the coprocessor (if any), but no memory transfers are 
requested.<BR><BR><B>Memory Waitstates</B><BR>Ideally, memory may be accessed 
free of waitstates (1N and 1S are then equal to 1 clock cycle each). However, a 
memory system may generate waitstates for several reasons: The memory may be 
just too slow. Memory is currently accessed by DMA, eg. sound, video, memory 
transfers, etc. Or when data is squeezed through a 16bit data bus (in that 
special case, 32bit access may have more waitstates than 8bit and 16bit 
accesses). Also, the memory system may separate between S and N cycles (if so, S 
cycles would be typically faster than N cycles).<BR><BR><B>Memory Waitstates for 
Different Memory Areas</B><BR>Different memory areas (eg. ROM and RAM) may have 
different waitstates. When executing code in one area which accesses data in 
another area, then the S+N cycles must be split into code and data accesses: 1N 
is used for data access, plus (n-1)S for LDM/STM, the remaining S+N are code 
access. If an instruction jumps to a different memory area, then all code cycles 
for that opcode are having waitstate characteristics of the NEW memory area 
(except Thumb BL which still executes 1S in OLD area).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpuversions></A><FONT size=+2>&nbsp;CPU 
  Versions</FONT></TD></TR></TBODY></TABLE><BR><B>Version Numbers</B><BR>ARM CPUs 
are distributed by name ARM#, and are described as ARMv# in specifications, 
whereas "#" is NOT the same than "v#", for example, ARM7TDMI is ARMv4TM. That is 
so confusing, that ARM didn't even attempt to clarify the relationship between 
the various "#" and "v#" values.<BR><BR><B>Version Variants</B><BR>Suffixes like 
"M" (long multiply), "T" (Thumb support), "E" (Enhanced DSP) indicate presence 
of special features, additionally to the standard instruction set of a given 
version, or, when preceded by an "x", indicate the absence of that 
features.<BR><BR><B>ARMv1 aka ARM1</B><BR>Some sort of a beta version, according 
to ARM never been used in any commercial products.<BR><BR><B>ARMv2 and 
up</B><BR>MUL,MLA<BR>CDP,LDC,MCR,MRC,STC<BR>SWP/SWPB (ARMv2a and up only)<BR>Two 
new FIQ registers<BR><BR><B>ARMv3 and up</B><BR>MRS,MSR opcodes (instead 
CMP/CMN/TST/TEQ{P} opcodes)<BR>CPSR,SPSR registers (instead PSR bits in 
R15)<BR>Removed never condition, cond=NV no longer valid<BR>32bit addressing 
(instead 26bit addressing in older versions)<BR>26bit addressing backwards 
comptibility mode (except v3G)<BR>Abt and Und modes (instead handling 
aborts/undefined in Svc mode)<BR>SMLAL,SMULL,UMLAL,UMULL (optionally, INCLUDED 
in v3M, EXCLUDED in v4xM/v5xM)<BR><BR><B>ARMv4 aka ARM7 and 
up</B><BR>LDRH,LDRSB,LDRSH,STRH<BR>Sys mode (privileged user mode)<BR>BX (only 
ARMv4T, and any ARMv5 or ARMv5T and up)<BR>THUMB code (only T variants, ie. 
ARMv4T, ARMv5T)<BR><BR><B>ARMv5 aka ARM9 and up</B><BR>BKPT,BLX,CLZ (BKPT,BLX 
also in THUMB mode)<BR>LDM/LDR/POP PC with mode switch (POP PC also in THUMB 
mode)<BR>CDP2,LDC2,MCR2,MRC2,STC2 (new coprocessor opcodes)<BR>C-flag unchanged 
by MUL (instead undefined flag value)<BR>changed instruction cycle timings / 
interlock ??? or not ???<BR>QADD,QDADD,QDSUB,QSUB opcodes, CPSR.Q flag (v5TE and 
V5TExP only)<BR>SMLAxy,SMLALxy,SMLAWy,SMULxy,SMULWy (v5TE and V5TExP 
only)<BR>LDRD,STRD,PLD,MCRR,MRRC (v5TE only, not v5, not 
v5TExP)<BR><BR><B>ARMv6</B><BR>No public specifications available.<BR><BR><B>A 
Milestone in Computer History</B><BR>Original ARMv2 has been used in the 
relative rare and expensive Archimedes deluxe home computers in the late 
eighties, the Archimedes has caught a lot of attention, particularly for being 
the first home computer that used a BIOS being programmed in BASIC language - 
which has been a absolutely revolutionary decadency at that time.<BR>Inspired, 
programmers all over the world have successfully developed even slower and much 
more inefficient programming languages, which are nowadays consequently used by 
nearly all ARM programmers, and by most non-ARM programmers as well.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=cpudatasheet></A><FONT size=+2>&nbsp;CPU Data 
  Sheet</FONT></TD></TR></TBODY></TABLE><BR>This present document is an attempt to 
supply a brief ARM7TDMI reference, hopefully including all information which is 
relevant for programmers.<BR><BR>Some details that I have treated as meaningless 
for GBA programming aren't included - such like Big Endian format, and Virtual 
Memory data aborts, and most of the chapters listed below.<BR><BR>Have a look at 
the complete data sheet (URL see below) for more detailed verbose information 
about ARM7TDMI instructions. That document also includes:<BR><BR>- Signal 
Description<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pins of the original CPU, probably other for GBA.
</PRE></TD></TR></TBODY></TABLE>- Memory Interface<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Optional virtual memory circuits, etc. not for GBA.
</PRE></TD></TR></TBODY></TABLE>- Coprocessor Interface<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  As far as I know, none such in GBA.
</PRE></TD></TR></TBODY></TABLE>- Debug Interface<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  For external hardware-based debugging.
</PRE></TD></TR></TBODY></TABLE>- ICEBreaker Module<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  For external hardware-based debugging also.
</PRE></TD></TR></TBODY></TABLE>- Instruction Cycle Operations<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Detailed: What happens during each cycle of each instruction.
</PRE></TD></TR></TBODY></TABLE>- DC Parameters (Power supply)<BR>- AC 
Parameters (Signal timings)<BR><BR>The official ARM7TDMI data sheet can be 
downloaded from ARMs webpage,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  http://www.arm.com/Documentation/UserMans/PDF/ARM7TDMI.html
</PRE></TD></TR></TBODY></TABLE>Be prepared for bloated PDF Format, approx 1.3 
MB, about 200 pages.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ndsreference></A><FONT size=+2>&nbsp;NDS 
  Reference</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dstechnicaldata">DS Technical 
Data</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsiomaps">DS I/O 
Maps</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsmemorymaps">DS Memory 
Maps</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrol">DS 
Memory Control</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsvideo">DS 
Video</A><BR><A href="http://nocash.emubase.de/gbatek.htm#ds3dvideo">DS 3D 
Video</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dssound">DS 
Sound</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dssystemandbuiltinperipherals">DS 
System and Built-in Peripherals</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgesencryptionfirmware">DS 
Cartridges, Encryption, Firmware</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsxboo">DS Xboo</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswirelesscommunications">DS Wireless 
Communications</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsbackwardscompatiblegbamode">DS 
Backwards-compatible GBA-Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosfunctions">BIOS 
Functions</A><BR><A href="http://nocash.emubase.de/gbatek.htm#cpureference">CPU 
Reference</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#externalconnectors">External 
Connectors</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dstechnicaldata></A><FONT size=+2>&nbsp;DS Technical 
      Data</FONT></TD></TR></TBODY></TABLE><BR><B>Processors</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1x ARM946E-S 32bit RISC CPU, 66MHz (NDS9 video) (not used in GBA mode)
  1x ARM7TDMI  32bit RISC CPU, 33MHz (NDS7 sound) (16MHz in GBA mode)
</PRE></TD></TR></TBODY></TABLE><B>Internal Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4096KB Main RAM (8192KB in debug version)
  96KB   WRAM (64K mapped to NDS7, plus 32K mappable to NDS7 or NDS9)
  60KB   TCM/Cache (TCM: 16K Data, 32K Code) (Cache: 4K Data, 8K Code)
  656KB  VRAM (allocateable as BG/OBJ/2D/3D/Palette/Texture/WRAM memory)
  4KB    OAM/PAL (2K OBJ Attribute Memory, 2K Standard Palette RAM)
  248KB  Internal 3D Memory (104K Polygon RAM, 144K Vertex RAM)
  ?KB    Matrix Stack, 48 scanline cache
  8KB    Wifi RAM
  256KB  Firmware FLASH (512KB in iQue variant, with chinese charset)
  36KB   BIOS ROM (4K NDS9, 16K NDS7, 16K GBA)
</PRE></TD></TR></TBODY></TABLE><B>Video</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2x LCD screens (each 256x192 pixel, 3 inch, 18bit color depth, backlight)
  2x 2D video engines (extended variants of the GBA's video controller)
  1x 3D video engine (can be assigned to upper or lower screen)
  1x video capture (for effects, or for forwarding 3D to the 2nd 2D engine)
</PRE></TD></TR></TBODY></TABLE><B>Sound</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  16 sound channels (16x PCM8/PCM16/IMA-ADPCM, 6x PSG-Wave, 2x PSG-Noise)
  2 sound capture units (for echo effects, etc.)
  Output: Two built-in stereo speakers, and headphones socket
  Input:  One built-in microphone, and microphone socket
</PRE></TD></TR></TBODY></TABLE><B>Controls</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Gamepad      4 Direction Keys, 8 Buttons
  Touchscreen  (on lower LCD screen)
</PRE></TD></TR></TBODY></TABLE><B>Communication Ports</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Wifi IEEE802.11b
</PRE></TD></TR></TBODY></TABLE><B>Specials</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Built-in Real Time Clock
  Power Managment Device
  Hardware divide and square root functions
  CP15 System Control Coprocessor (cache, tcm, pu, bist, etc.)
</PRE></TD></TR></TBODY></TABLE><B>External Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS Slot (for NDS games) (encrypted 8bit data bus, and serial 1bit bus)
  GBA Slot (for NDS expansions, or for GBA games) (but not for DMG/CGB games)
</PRE></TD></TR></TBODY></TABLE><B>Manufactured Cartridges</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ROM: 16MB, 32MB, or 64MB
  EEPROM/FLASH/FRAM: 0.5KB, 8KB, 64KB, 256KB, or 512KB
</PRE></TD></TR></TBODY></TABLE><B>Can be booted from</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS Cartridge (NDS mode)
  Firmware FLASH (NDS mode) (eg. by patching firmware via ds-xboo cable)
  Wifi (NDS mode)
  GBA Cartridge (GBA mode) (without DMG/CGB support) (without SIO support)
</PRE></TD></TR></TBODY></TABLE><B>Power Supply</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Built-in rechargeable Lithium ion battery, 3.7V 1000mAh (DS-Lite)
  External Supply: 5.2V DC
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS-Lite</B><BR>Slightly smaller than the 
original NDS, coming in a more decently elegant case. The LCDs are much more 
colorful (and thus not backwards compatible with any older NDS or GBA games), 
and the LCDs support wider viewing angles. Slightly different power managment 
device (with selectable backlight brightness, new external power source flag, 
lost audio amplifier mute flag). Slightly different Wifi controller (different 
chip ID, different dirt effects when accessing invalid wifi ports and unused 
wifi memory regions, different behaviour on GAPDISP registers, RF/BB chips 
replaced by a single chip). Slightly different touch screen controller (with new 
unused input, and slightly different powerdown 
bits).<BR><BR><B>Notice</B><BR>NDS9 means the ARM9 processor and its memory and 
I/O ports in NDS mode<BR>NDS7 means the ARM7 processor and its memory and I/O 
ports in NDS mode<BR>GBA means the ARM7 processor and its memory and I/O ports 
in GBA mode<BR><BR><B>The two Processors</B><BR>Most game code is usually 
executed on the ARM9 processor (in fact, Nintendo reportedly doesn't allow 
developers use the ARM7 processor, except by predefined API functions, anyways, 
even with the most likely inefficient API code, most of the ARM7's 33MHz 
horsepower is left unused).<BR>The ARM9's 66MHz "horsepower" is a different tale 
- it seems Nintendo thought that a 33MHz processor would be too "slow" for 3D 
games, and so they (tried to) badge an additional CPU to the original GBA 
hardware.<BR>However, the real 66MHz can be used only with cache and tcm, all 
other memory and I/O accesses are delayed to the 33MHz bus clock, that'd be 
still quite fast, but, there seems to be a hardware glitch that adds 3 
waitcycles to all nonsequential accesses at the NDS9 side, which effectively 
drops its bus clock to about 8MHz, making it ways slower than the 33MHz NDS7 
processor, it's even slower than the original 16MHz GBA 
processor.<BR>Altogether, with the bugged 66MHz, and the unused 33MHz, Nintendo 
could have reached almost the same power when staying with the GBA's 16MHz 
processor :-)<BR>Although, when properly using cache/tcm, then the 66MHz 
processor &lt;can&gt; be very fast, still, the NDS should have worked as well 
with a single processor, though using only an ARM9 might cause a lot of 
compatibilty problems with GBA games, so there's at least one reason for keeping 
the ARM7 included.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsiomaps></A><FONT size=+2>&nbsp;DS I/O 
  Maps</FONT></TD></TR></TBODY></TABLE><BR>ARM9 I/O Map<BR><B>Display Engine 
A</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000000h  4    2D Engine A - DISPCNT - LCD Control (Read/Write)
  4000004h  2    2D Engine A+B - DISPSTAT - General LCD Status (Read/Write)
  4000006h  2    2D Engine A+B - VCOUNT - Vertical Counter (Read only)
  4000008h  50h  2D Engine A (same registers as GBA, some changed bits)
  4000060h  2    DISP3DCNT - 3D Display Control Register (R/W)
  4000064h  4    DISPCAPCNT - Display Capture Control Register (R/W)
  4000068h  4    DISP_MMEM_FIFO - Main Memory Display FIFO (R?/W)
  400006Ch  2    2D Engine A - MASTER_BRIGHT - Master Brightness Up/Down
</PRE></TD></TR></TBODY></TABLE><B>DMA, Timers, and Keypad</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  40000B0h  30h  DMA Channel 0..3
  40000E0h  10h  DMA FILL Registers for Channel 0..3
  4000100h  10h  Timers 0..3
  4000130h  2    KEYINPUT
  4000132h  2    KEYCNT
</PRE></TD></TR></TBODY></TABLE><B>IPC/ROM</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000180h  2  IPCSYNC - IPC Synchronize Register (R/W)
  4000184h  2  IPCFIFOCNT - IPC Fifo Control Register (R/W)
  4000188h  4  IPCFIFOSEND - IPC Send Fifo (W)
  40001A0h  2  AUXSPICNT - Gamecard ROM and SPI Control
  40001A2h  2  AUXSPIDATA - Gamecard SPI Bus Data/Strobe
  40001A4h  4  Gamecard bus timing/control
  40001A8h  8  Gamecard bus 8-byte command out
  40001B0h  4  Gamecard Encryption Seed 0 Lower 32bit
  40001B4h  4  Gamecard Encryption Seed 1 Lower 32bit
  40001B8h  2  Gamecard Encryption Seed 0 Upper 7bit (bit8-15 unused)
  40001BAh  2  Gamecard Encryption Seed 1 Upper 7bit (bit8-15 unused)
</PRE></TD></TR></TBODY></TABLE><B>Memory and IRQ Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000204h  2  EXMEMCNT - External Memory Control (R/W)
  4000208h  2  IME - Interrupt Master Enable (R/W)
  4000210h  4  IE  - Interrupt Enable (R/W)
  4000214h  4  IF  - Interrupt Request Flags (R/W)
  4000240h  1  VRAMCNT_A - VRAM-A (128K) Bank Control (W)
  4000241h  1  VRAMCNT_B - VRAM-B (128K) Bank Control (W)
  4000242h  1  VRAMCNT_C - VRAM-C (128K) Bank Control (W)
  4000243h  1  VRAMCNT_D - VRAM-D (128K) Bank Control (W)
  4000244h  1  VRAMCNT_E - VRAM-E (64K) Bank Control (W)
  4000245h  1  VRAMCNT_F - VRAM-F (16K) Bank Control (W)
  4000246h  1  VRAMCNT_G - VRAM-G (16K) Bank Control (W)
  4000247h  1  WRAMCNT   - WRAM Bank Control (W)
  4000248h  1  VRAMCNT_H - VRAM-H (32K) Bank Control (W)
  4000249h  1  VRAMCNT_I - VRAM-I (16K) Bank Control (W)
</PRE></TD></TR></TBODY></TABLE><B>Maths</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000280h  2  DIVCNT - Division Control (R/W)
  4000290h  8  DIV_NUMER - Division Numerator (R/W)
  4000298h  8  DIV_DENOM - Division Denominator (R/W)
  40002A0h  8  DIV_RESULT - Division Quotient (=Numer/Denom) (R/W?)
  40002A8h  8  DIVREM_RESULT - Division Remainder (=Numer MOD Denom) (R/W?)
  40002B0h  2  SQRTCNT - Square Root Control (R/W)
  40002B4h  4  SQRT_RESULT - Square Root Result (R/W?)
  40002B8h  8  SQRT_PARAM - Square Root Parameter Input (R/W)
  4000300h  4  POSTFLG - Undoc
  4000304h  2  POWCNT1 - Graphics Power Control Register (R/W)
</PRE></TD></TR></TBODY></TABLE><B>3D Display Engine</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000320h..6A3h
</PRE></TD></TR></TBODY></TABLE><B>Display Engine B</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4001000h  4    2D Engine B - DISPCNT - LCD Control (Read/Write)
  4001008h  50h  2D Engine B (same registers as GBA, some changed bits)
  400106Ch  2    2D Engine B - MASTER_BRIGHT - 16bit - Brightness Up/Down
</PRE></TD></TR></TBODY></TABLE><B>IPC/ROM</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4100000h  4    IPCFIFORECV - IPC Receive Fifo (R)
  4100010h  4    Gamecard bus 4-byte data in, for manual or dma read
</PRE></TD></TR></TBODY></TABLE><B>Hardcoded RAM Addresses for Exception 
Handling</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  27FFD9Ch   ..  NDS9 Debug Stacktop / Debug Vector (0=None)
  DTCM+3FF8h 4   NDS9 IRQ Check Bits (hardcoded RAM address)
  DTCM+3FFCh 4   NDS9 IRQ Handler (hardcoded RAM address)
</PRE></TD></TR></TBODY></TABLE><B>Main Memory Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  27FFFFEh  2    Main Memory Control
</PRE></TD></TR></TBODY></TABLE><B>Further Memory Control Registers</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR><BR><B>ARM7 I/O Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000004h  2   DISPSTAT
  4000006h  2   VCOUNT
  40000B0h  30h DMA Channels 0..3
  4000100h  10h Timers 0..3
  4000120h  4   Debug SIODATA32
  4000128h  4   Debug SIOCNT
  4000130h  2   keyinput
  4000132h  2   keycnt
  4000134h  2   Debug RCNT
  4000136h  2   EXTKEYIN
  4000138h  1   RTC Realtime Clock Bus
  4000180h  2   IPCSYNC - IPC Synchronize Register (R/W)
  4000184h  2   IPCFIFOCNT - IPC Fifo Control Register (R/W)
  4000188h  4   IPCFIFOSEND - IPC Send Fifo (W)
  40001A0h  2   AUXSPICNT - Gamecard ROM and SPI Control
  40001A2h  2   AUXSPIDATA - Gamecard SPI Bus Data/Strobe
  40001A4h  4   Gamecard bus timing/control
  40001A8h  8   Gamecard bus 8-byte command out
  40001B0h  4   Gamecard Encryption Seed 0 Lower 32bit
  40001B4h  4   Gamecard Encryption Seed 1 Lower 32bit
  40001B8h  2   Gamecard Encryption Seed 0 Upper 7bit (bit8-15 unused)
  40001BAh  2   Gamecard Encryption Seed 1 Upper 7bit (bit8-15 unused)
  40001C0h  2   SPI bus Control (Firmware, Touchscreen, Powerman)
  40001C2h  2   SPI bus Data
</PRE></TD></TR></TBODY></TABLE><B>Memory and IRQ Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000204h  2   EXMEMSTAT - External Memory Status
  4000206h  2   WIFIWAITCNT
  4000208h  4   IME
  4000210h  4   IE
  4000214h  4   IF
  4000240h  1   VRAMSTAT - VRAM-C,D Bank Status (R)
  4000241h  1   WRAMSTAT - WRAM Bank Status (R)
  4000300h  1   POSTFLG
  4000301h  1   HALTCNT (different bits than on GBA) (plus NOP delay)
  4000304h  2   POWCNT2  Sound/Wifi Power Control Register (R/W)
  4000308h  4   BIOSPROT - Bios-data-read-protection address
</PRE></TD></TR></TBODY></TABLE><B>Sound Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4000400h 100h Sound Channel 0..15 (10h bytes each)
  40004x0h  4  SOUNDxCNT - Sound Channel X Control Register (R/W)
  40004x4h  4  SOUNDxSAD - Sound Channel X Data Source Register (W)
  40004x8h  2  SOUNDxTMR - Sound Channel X Timer Register (W)
  40004xAh  2  SOUNDxPNT - Sound Channel X Loopstart Register (W)
  40004xCh  4  SOUNDxLEN - Sound Channel X Length Register (W)
  4000500h  2  SOUNDCNT - Sound Control Register (R/W)
  4000504h  2  SOUNDBIAS - Sound Bias Register (R/W)
  4000508h  1  SNDCAP0CNT - Sound Capture 0 Control Register (R/W)
  4000509h  1  SNDCAP1CNT - Sound Capture 1 Control Register (R/W)
  4000510h  4  SNDCAP0DAD - Sound Capture 0 Destination Address (R/W)
  4000514h  2  SNDCAP0LEN - Sound Capture 0 Length (W)
  4000518h  4  SNDCAP1DAD - Sound Capture 1 Destination Address (R/W)
  400051Ch  2  SNDCAP1LEN - Sound Capture 1 Length (W)
</PRE></TD></TR></TBODY></TABLE><B>IPC/ROM</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4100000h  4   IPCFIFORECV - IPC Receive Fifo (R)
  4100010h  4   Gamecard bus 4-byte data in, for manual or dma read
</PRE></TD></TR></TBODY></TABLE><B>WLAN Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4800000h  ..  Wifi WS0 Region (32K) (Wifi Ports, and 8K Wifi RAM)
  4808000h  ..  Wifi WS1 Region (32K) (mirror of above, other waitstates)
</PRE></TD></TR></TBODY></TABLE><B>Hardcoded RAM Addresses for Exception 
Handling</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  380FFDCh  ..  NDS7 Debug Stacktop / Debug Vector (0=None)
  380FFF8h  4   NDS7 IRQ Check Bits (hardcoded RAM address)
  380FFFCh  4   NDS7 IRQ Handler (hardcoded RAM address)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorymaps></A><FONT size=+2>&nbsp;DS Memory 
  Maps</FONT></TD></TR></TBODY></TABLE><BR><B>NDS9 Memory Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000h  Instruction TCM (32KB) (not moveable) (mirror-able to 1000000h)
  0xxxx000h  Data TCM        (16KB) (moveable)
  02000000h  Main Memory     (4MB)
  03000000h  Shared WRAM     (0KB, 16KB, or 32KB can be allocated to ARM9)
  04000000h  ARM9-I/O Ports
  05000000h  Standard Palettes (2KB) (Engine A BG/OBJ, Engine B BG/OBJ)
  06000000h  VRAM - Engine A, BG VRAM  (max 512KB)
  06200000h  VRAM - Engine B, BG VRAM  (max 128KB)
  06400000h  VRAM - Engine A, OBJ VRAM (max 256KB)
  06600000h  VRAM - Engine B, OBJ VRAM (max 128KB)
  06800000h  VRAM - "LCDC"-allocated (max 656KB)
  07000000h  OAM (2KB) (Engine A, Engine B)
  08000000h  GBA Slot ROM (max. 32MB)
  0A000000h  GBA Slot RAM (max. 64KB)
  FFFF0000h  ARM9-BIOS (32KB) (only 3K used)
</PRE></TD></TR></TBODY></TABLE>The ARM9 Exception Vectors are located at 
FFFF0000h. The IRQ handler redirects to [DTCM+3FFCh].<BR><BR><B>NDS7 Memory 
Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000000h  ARM7-BIOS (16KB)
  02000000h  Main Memory (4MB)
  03000000h  Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM7)
  03800000h  ARM7-WRAM (64KB)
  04000000h  ARM7-I/O Ports
  04800000h  Wireless Communications Wait State 0 (8KB RAM at 4804000h)
  04808000h  Wireless Communications Wait State 1 (I/O Ports at 4808000h)
  06000000h  VRAM allocated as Work RAM to ARM7 (max. 256K)
  08000000h  GBA Slot ROM (max. 32MB)
  0A000000h  GBA Slot RAM (max. 64KB)
</PRE></TD></TR></TBODY></TABLE>The ARM7 Exception Vectors are located at 
00000000h. The IRQ handler redirects to [3FFFFFCh aka 
380FFFCh].<BR><BR><B>Further Memory (not mapped to ARM9/ARM7 bus)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  3D Engine Polygon RAM (52KBx2)
  3D Engine Vertex RAM (72KBx2)
  Firmware (256KB) (built-in serial flash memory)
  GBA-BIOS (16KB) (not used in NDS mode)
  NDS Slot ROM (serial 8bit-bus, max. 4GB with default protocol)
  NDS Slot FLASH/EEPROM/FRAM (serial 1bit-bus)
</PRE></TD></TR></TBODY></TABLE><BR><B>Shared-RAM</B><BR>Even though Shared WRAM 
begins at 3000000h, programs are commonly using mirrors at 37F8000h (both ARM9 
and ARM7). At the ARM7-side, this allows to use 32K Shared WRAM and 64K 
ARM7-WRAM as a continous 96K RAM block.<BR><BR><B>Undefined I/O Ports</B><BR>On 
the NDS (at the ARM9-side at least) undefined I/O ports are always 
zero.<BR><BR><B>Undefined Memory Regions</B><BR>16MB blocks that do not contain 
any defined memory regions (or that contain only mapped TCM regions) are 
typically completely undefined.<BR>16MB blocks that do contain valid memory 
regions are typically containing mirrors of that memory in the unused upper part 
of the 16MB area (only exceptions are TCM and BIOS which are not 
mirrored).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrol></A><FONT size=+2>&nbsp;DS Memory 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>Memory Control</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolcacheandtcm">DS Memory 
Control - Cache and TCM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolcartridgesandmainram">DS 
Memory Control - Cartridges and Main RAM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolwram">DS Memory Control 
- WRAM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolvram">DS Memory Control 
- VRAM</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolbios">DS Memory Control 
- BIOS</A><BR><BR><B>Memory Access Time</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorytimings">DS Memory 
Timings</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrolcacheandtcm></A><FONT size=+2>&nbsp;DS Memory 
      Control - Cache and TCM</FONT></TD></TR></TBODY></TABLE><BR>TCM and Cache are 
controlled by the System Control Coprocessor,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR><BR>The specifications for the NDS9 
are:<BR><BR><B>Tightly Coupled Memory (TCM)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ITCM 32K, base=00000000h (fixed, not move-able)
  DTCM 16K, base=moveable  (default base=27C0000h)
</PRE></TD></TR></TBODY></TABLE>Note: Although ITCM is NOT moveable, the NDS 
Firmware configures the ITCM size to 32MB, and so, produces ITCM mirrors at 
0..1FFFFFFh. Furthermore, the PU can be used to lock/unlock memory in that 
region. That trick allows to move ITCM anywhere within the lower 32MB of 
memory.<BR><BR><B>Cache</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Data Cache 4KB, Instruction Cache 8KB
  4-way set associative method
  Cache line 8 words (32 bytes)
  Read-allocate method (ie. writes are not allocating cache lines)
  Round-robin and Pseudo-random replacement algorithms selectable
  Cache Lockdown, Instruction Prefetch, Data Preload
  Data write-through and write-back modes selectable
</PRE></TD></TR></TBODY></TABLE><BR><B>Protection Unit 
(PU)</B><BR>Recommended/default settings are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Region  Name            Address   Size   Cache WBuf Code Data
  -       Background      00000000h 4GB    -     -    -    -
  0       I/O and VRAM    04000000h 64MB   -     -    R/W  R/W
  1       Main Memory     02000000h 4MB    On    On   R/W  R/W
  2       ARM7-dedicated  027C0000h 256KB  -     -    -    -
  3       GBA Slot        08000000h 128MB  -     -    -    R/W
  4       DTCM            027C0000h 16KB   -     -    -    R/W
  5       ITCM            01000000h 32KB   -     -    R/W  R/W
  6       BIOS            FFFF0000h 32KB   On    -    R    R
  7       Shared Work     027FF000h 4KB    -     -    -    R/W
</PRE></TD></TR></TBODY></TABLE>Notes: In Nintendo's hardware-debugger, Main 
Memory is expanded to 8MB (for that reason, some addresses are at 27NN000h 
instead 23NN000h) (some of the extra memory is reserved for the debugger, some 
can be used for game development). Region 2 and 7 are not understood? GBA Slot 
should be max 32MB+64KB, rounded up to 64MB, no idea why it is 128MB? DTCM and 
ITCM do not use Cache and Write-Buffer because TCM is fast. Above settings do 
not allow to access Shared Memory at 37F8000h? Do not use cache/wbuf for I/O, 
doing so might suppress writes, and/or might read outdated values.<BR>The main 
purpose of the Protection Unit is debugging, a major problem with GBA programs 
have been faulty accesses to memory address 00000000h and up (due to 
[base+offset] addressing with uninitialized (zero) base values). This problem 
has been fixed in the NDS, for the ARM9 processor at least, still there are 
various leaks: For example, the 64MB I/O and VRAM area contains only ca. 660KB 
valid addresses, and the ARM7 probably doesn't have a Protection Unit at all. 
Alltogether, the protection is better than in GBA, but it's still pretty crude 
compared with software debugging tools.<BR>Region address/size are unified (same 
for code and data), however, cachabilty and access rights are non-unified (and 
may be separately defined for code and data).<BR><BR>Note: The NDS7 doesn't have 
any TCM, Cache, or CP15.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrolcartridgesandmainram></A><FONT size=+2>&nbsp;DS 
      Memory Control - Cartridges and Main 
RAM</FONT></TD></TR></TBODY></TABLE><BR><B>4000204h - NDS9 - EXMEMCNT - 16bit - 
External Memory Control (R/W)</B><BR><B>4000204h - NDS7 - EXMEMSTAT - 16bit - 
External Memory Status (R/W..R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   32-pin GBA Slot SRAM Access Time    (0-3 = 10, 8, 6, 18 cycles)
  2-3   32-pin GBA Slot ROM 1st Access Time (0-3 = 10, 8, 6, 18 cycles)
  4     32-pin GBA Slot ROM 2nd Access Time (0-1 = 6, 4 cycles)
  5-6   32-pin GBA Slot PHI-pin out   (0-3 = Low, 4.19MHz, 8.38MHz, 16.76MHz)
  7     32-pin GBA Slot Access Rights     (0=ARM9, 1=ARM7)
  8-10  Not used (always zero)
  11    17-pin NDS Slot Access Rights     (0=ARM9, 1=ARM7)
  12    Not used (always zero)
  13    Not used (always set ?)
  14    Main Memory Interface Mode Switch (0=Async/GBA/Reserved, 1=Synchronous)
  15    Main Memory Access Priority       (0=ARM9 Priority, 1=ARM7 Priority)
</PRE></TD></TR></TBODY></TABLE>Bit0-6 can be changed by both NDS9 and NDS7, 
changing these bits affects the local EXMEM register only, not that of the other 
CPU.<BR>Bit7-15 can be changed by NDS9 only, changing these bits affects both 
EXMEM registers, ie. both NDS9 and NDS7 can read the current NDS9 
setting.<BR>Bit14=0 is intended for GBA mode, however, writes to this bit appear 
to be ignored?<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmainmemorycontrol">DS Main Memory 
Control</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrolwram></A><FONT size=+2>&nbsp;DS Memory Control 
      - WRAM</FONT></TD></TR></TBODY></TABLE><BR><B>4000247h - NDS9 - WRAMCNT - 8bit - 
WRAM Bank Control (R/W)</B><BR><B>4000241h - NDS7 - WRAMSTAT - 8bit - WRAM Bank 
Status (R)</B><BR>Should not be changed when using Nintendo's API.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   ARM9/ARM7 (0-3 = 32K/0K, 2nd 16K/1st 16K, 1st 16K/2nd 16K, 0K/32K)
  2-7   Not used
</PRE></TD></TR></TBODY></TABLE>The ARM9 WRAM area is 3000000h-3FFFFFFh (16MB 
range).<BR>The ARM7 WRAM area is 3000000h-37FFFFFh (8MB range).<BR>The allocated 
16K or 32K are mirrored everywhere in the above areas.<BR>De-allocation (0K) is 
a special case: At the ARM9-side, the WRAM area is then empty (containing 
undefined data). At the ARM7-side, the WRAM area is then containing mirrors of 
the 64KB ARM7-WRAM (the memory at 3800000h and up).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrolvram></A><FONT size=+2>&nbsp;DS Memory Control 
      - VRAM</FONT></TD></TR></TBODY></TABLE><BR><B>4000240h - NDS7 - VRAMSTAT - 8bit 
- VRAM Bank Status (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     VRAM C enabled and allocated to NDS7  (0=No, 1=Yes)
  1     VRAM D enabled and allocated to NDS7  (0=No, 1=Yes)
  2-7   Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>The register indicates if VRAM C/D are allocated 
to NDS7 (as Work RAM), ie. if VRAMCNT_C/D are enabled (Bit7=1), with MST=2 
(Bit0-2). However, it does not reflect the OFS value.<BR><BR><B>4000240h - NDS9 
- VRAMCNT_A - 8bit - VRAM-A (128K) Bank Control (W)</B><BR><B>4000241h - NDS9 - 
VRAMCNT_B - 8bit - VRAM-B (128K) Bank Control (W)</B><BR><B>4000242h - NDS9 - 
VRAMCNT_C - 8bit - VRAM-C (128K) Bank Control (W)</B><BR><B>4000243h - NDS9 - 
VRAMCNT_D - 8bit - VRAM-D (128K) Bank Control (W)</B><BR><B>4000244h - NDS9 - 
VRAMCNT_E - 8bit - VRAM-E (64K) Bank Control (W)</B><BR><B>4000245h - NDS9 - 
VRAMCNT_F - 8bit - VRAM-F (16K) Bank Control (W)</B><BR><B>4000246h - NDS9 - 
VRAMCNT_G - 8bit - VRAM-G (16K) Bank Control (W)</B><BR><B>4000248h - NDS9 - 
VRAMCNT_H - 8bit - VRAM-H (32K) Bank Control (W)</B><BR><B>4000249h - NDS9 - 
VRAMCNT_I - 8bit - VRAM-I (16K) Bank Control (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-2   VRAM MST              ;Bit2 not used by VRAM-A,B,H,I
  3-4   VRAM Offset (0-3)     ;Offset not used by VRAM-E,H,I
  5-6   Not used
  7     VRAM Enable (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE>There is a total of 656KB of VRAM in Blocks 
A-I.<BR>Table below shows the possible configurations.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  VRAM    SIZE  MST  OFS   ARM9, Plain ARM9-CPU Access (so-called LCDC mode)</B>
  A       128K  0    -     6800000h-681FFFFh
  B       128K  0    -     6820000h-683FFFFh
  C       128K  0    -     6840000h-685FFFFh
  D       128K  0    -     6860000h-687FFFFh
  E       64K   0    -     6880000h-688FFFFh
  F       16K   0    -     6890000h-6893FFFh
  G       16K   0    -     6894000h-6897FFFh
  H       32K   0    -     6898000h-689FFFFh
  I       16K   0    -     68A0000h-68A3FFFh
<B>  VRAM    SIZE  MST  OFS   ARM9, 2D Graphics Engine A, BG-VRAM (max 512K)</B>
  A,B,C,D 128K  1    0..3  6000000h+(20000h*OFS)
  E       64K   1    -     6000000h
  F,G     16K   1    0..3  6000000h+(4000h*OFS.0)+(10000h*OFS.1)
<B>  VRAM    SIZE  MST  OFS   ARM9, 2D Graphics Engine A, OBJ-VRAM (max 256K)</B>
  A,B     128K  2    0..1  6400000h+(20000h*OFS.0)  ;(OFS.1 must be zero)
  E       64K   2    -     6400000h
  F,G     16K   2    0..3  6400000h+(4000h*OFS.0)+(10000h*OFS.1)
<B>  VRAM    SIZE  MST  OFS   2D Graphics Engine A, BG Extended Palette</B>
  E       64K   4    -     Slot 0-3  ;only lower 32K used
  F,G     16K   4    0..1  Slot 0-1 (OFS=0), Slot 2-3 (OFS=1)
<B>  VRAM    SIZE  MST  OFS   2D Graphics Engine A, OBJ Extended Palette</B>
  F,G     16K   5    -     Slot 0  ;16K each (only lower 8K used)
<B>  VRAM    SIZE  MST  OFS   Texture/Rear-plane Image</B>
  A,B,C,D 128K  3    0..3  Slot OFS(0-3)   ;(Slot2-3: Texture, or Rear-plane)
<B>  VRAM    SIZE  MST  OFS   Texture Palette</B>
  E       64K   3    -     Slots 0-3                 ;OFS=don't care
  F,G     16K   3    0..3  Slot (OFS.0*1)+(OFS.1*4)  ;ie. Slot 0, 1, 4, or 5
<B>  VRAM    SIZE  MST  OFS   ARM9, 2D Graphics Engine B, BG-VRAM (max 128K)</B>
  C       128K  4    -     6200000h
  H       32K   1    -     6200000h
  I       16K   1    -     6208000h
<B>  VRAM    SIZE  MST  OFS   ARM9, 2D Graphics Engine B, OBJ-VRAM (max 128K)</B>
  D       128K  4    -     6600000h
  I       16K   2    -     6600000h
<B>  VRAM    SIZE  MST  OFS   2D Graphics Engine B, BG Extended Palette</B>
  H       32K   2    -     Slot 0-3
<B>  VRAM    SIZE  MST  OFS   2D Graphics Engine B, OBJ Extended Palette</B>
  I       16K   3    -     Slot 0  ;(only lower 8K used)
<B>  VRAM    SIZE  MST  OFS   &lt;ARM7&gt;, Plain &lt;ARM7&gt;-CPU Access</B>
  C,D     128K  2    0..1  6000000h+(20000h*OFS.0)  ;OFS.1 must be zero
</PRE></TD></TR></TBODY></TABLE><BR><B>Notes</B><BR>In Plain-CPU modes, VRAM can 
be accessed only by the CPU (and by the Capture Unit, and by VRAM Display mode). 
In "Plain &lt;ARM7&gt;-CPU Access" mode, the VRAM blocks are allocated as Work 
RAM to the NDS7 CPU.<BR>In BG/OBJ VRAM modes, VRAM can be accessed by the CPU at 
specified addresses, and by the display controller.<BR>In Extended Palette and 
Texture Image/Palette modes, VRAM is not mapped to CPU address space, and can be 
accessed only by the display controller (so, to initialize or change the memory, 
it should be temporarily switched to Plain-CPU mode).<BR>All VRAM (and Palette, 
and OAM) can be written to only in 16bit and 32bit units (STRH, STR opcodes), 
8bit writes are ignored (by STRB opcode). The only exception is "Plain 
&lt;ARM7&gt;-CPU Access" mode: The ARM7 CPU can use STRB to write to VRAM (the 
reason for this special feature is that, in GBA mode, two 128K VRAM blocks are 
used to emulate the GBA's 256K Work RAM).<BR><BR><B>Other Video RAM</B><BR>Aside 
from the map-able VRAM blocks, there are also some video-related memory regions 
at fixed addresses:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  5000000h Engine A Standard BG Palette (512 bytes)
  5000200h Engine A Standard OBJ Palette (512 bytes)
  5000400h Engine B Standard BG Palette (512 bytes)
  5000600h Engine B Standard OBJ Palette (512 bytes)
  7000000h Engine A OAM (1024 bytes)
  7000400h Engine B OAM (1024 bytes)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorycontrolbios></A><FONT size=+2>&nbsp;DS Memory Control 
      - BIOS</FONT></TD></TR></TBODY></TABLE><BR><B>4000308h - NDS7 - BIOSPROT - 
Bios-data-read-protection address</B><BR>Used to double-protect the first some 
KBytes of the NDS7 BIOS. The BIOS is split into two protection regions, one 
always active, one controlled by the BIOSPROT register. The overall idea is that 
only the BIOS can read from itself, any other attempts to read from that regions 
return FFh-bytes.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Opcodes at...      Can read from      Expl.
  0..[BIOSPROT]-1    0..3FFFh           Double-protected (when BIOSPROT is set)
  [BIOSPROT]..3FFFh  [BIOSPROT]..3FFFh  Normal-protected (always active)
</PRE></TD></TR></TBODY></TABLE>The initial BIOSPROT setting on power-up is zero 
(disabled). Before starting the cartridge, the BIOS boot code sets the register 
to 1204h (actually 1205h, but the mis-aligned low-bit is ignored). Once when 
initialized, further writes to the register are ignored.<BR><BR>The 
double-protected region contains the exception vectors, some bytes of code, and 
the cartridge KEY1 encryption seed (about 4KBytes). As far as I know, it is 
impossible to unlock the memory once when it is locked, however, with some 
trickery, it is possible execute code before it gets locked. Also, the two THUMB 
opcodes at 05ECh can be used to read all memory at 0..3FFFh,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  05ECh  ldrb r3,[r3,12h]      ;requires incoming r3=src-12h
  05EEh  pop  r2,r4,r6,r7,r15  ;requires dummy values &amp; THUMB retadr on stack
</PRE></TD></TR></TBODY></TABLE>Additionally most BIOS functions (eg. CpuSet), 
include a software-based protection which rejects source addresses in the BIOS 
area (the only exception is GetCRC16, though it still cannot bypass the BIOSPROT 
setting).<BR><BR><B>Note</B><BR>The NDS9 BIOS doesn't include any software or 
hardware based read protection.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmemorytimings></A><FONT size=+2>&nbsp;DS Memory 
      Timings</FONT></TD></TR></TBODY></TABLE><BR><B>System Clock</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bus clock  = 33MHz (33.513982 MHz) (1FF61FEh Hertz)
  NDS7 clock = 33MHz (same as bus clock)
  NDS9 clock = 66MHz (internally twice bus clock; for cache/tcm)
</PRE></TD></TR></TBODY></TABLE>Most timings in this document are specified for 
33MHz clock (not for the 66MHz clock). Respectively, NDS9 timings are counted in 
"half" cycles.<BR><BR><B>Memory Access Times</B><BR>Tables below show the 
different access times for code/data fetches on arm7/arm9 cpus, measured for 
sequential/nonsequential 32bit/16bit accesses.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS7/CODE             NDS9/CODE
  N32 S32 N16 S16 Bus   N32 S32 N16 S16 Bus
  9   2   8   1   16    9   9   4.5 4.5 16  Main RAM (read) (cache off)
  1   1   1   1   32    4   4   2   2   32  WRAM,BIOS,I/O,OAM
  2   2   1   1   16    5   5   2.5 2.5 16  VRAM,Palette RAM
  16  12  10  6   16    19  19  9.5 9.5 16  GBA ROM (example 10,6 access)
  -   -   -   -   -     0.5 0.5 0.5 0.5 32  TCM, Cache_Hit
  -   -   -   -   -     (--Load 8 words--)  Cache_Miss
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS7/DATA             NDS9/DATA
  N32 S32 N16 S16 Bus   N32 S32 N16 S16 Bus
  10  2   9   1   16    10  2   9   1   16  Main RAM (read) (cache off)
  1   1   1   1   32    4   1   4   1   32  WRAM,BIOS,I/O,OAM
  1?  2   1   1   16    5   2   4   1   16  VRAM,Palette RAM
  15  12  9   6   16    19  12  13  6   16  GBA ROM (example 10,6 access)
  9   10  9   10  8     13  10  13  10  8   GBA RAM (example 10 access)
  -   -   -   -   -     0.5 0.5 0.5 -   32  TCM, Cache_Hit
  -   -   -   -   -     (--Load 8 words--)  Cache_Miss
  -   -   -   -   -     11  11  11  -   32  Cache_Miss (BIOS)
  -   -   -   -   -     23  23  23  -   16  Cache_Miss (Main RAM)
</PRE></TD></TR></TBODY></TABLE>All timings are counted in 33MHz units (so 
"half" cycles can occur on NDS9).<BR>Note: 8bit data accesses have same timings 
than 16bit data.<BR><BR>*** DS Memory Timing Notes ***<BR><BR>The NDS timings 
are altogether pretty messed up, with different timings for CODE and DATA 
fetches, and different timings for NDS7 and 
NDS9...<BR><BR><B>NDS7/CODE</B><BR>Timings for this region can be considered as 
"should be" timings.<BR><BR><B>NDS7/DATA</B><BR>Quite the same as NDS7/CODE. 
Except that, nonsequently Main RAM accesses are 1 cycle slower, and more 
strange, nonsequential GBA Slot accesses are 1 cycle 
faster.<BR><BR><B>NDS9/CODE</B><BR>This is the most messiest timing. An infamous 
PENALTY of 3 cycles is added to all nonsequential accesses (except cache, tcm, 
and main ram). And, all opcode fetches are forcefully made nonsequential 32bit 
(the NDS9 simply doesn't support fast sequential opcode fetches). That applies 
also for THUMB code (two 16bit opcodes are fetched by a single nonsequential 
32bit access) (so the time per 16bit opcode is one half of the 32bit fetch) 
(unless a branch causes only one of the two 16bit opocdes to be executed, then 
that opcode will have the full 32bit access 
time).<BR><BR><B>NDS9/DATA</B><BR>Allows both sequential and nonsequential 
access, and both 16bit and 32bit access, so it's faster than NDS9/CODE. 
Nethertheless, it's still having the 3 cycle PENALTY on nonsequential accesses. 
And, similar as NDS7/DATA, it's also adding 1 cycle to nonsequential Main RAM 
accesses.<BR><BR>*** More Timing Notes / Lots of unsorted Info 
***<BR><BR><B>Actual CPU Performance</B><BR>The 33MHz NDS7 is running more or 
less nicely at 33MHz. However, the so-called "66MHz" NDS9 is having &lt;much&gt; 
higher waitstates, and it's effective bus speed is barely about 8..16MHz, the 
only exception is code/data in cache/tcm, which is eventually reaching real 
66MHz (that, assuming cache HITS, otherwise, in case of cache MISSES, the cached 
memory timing might even drop to 1.4MHz or 
so?).<BR>*********************<BR>ARM9 opcode fetches are always N32 + 3 
waits.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  S16 and N16 do not exist (because thumb-double-fetching) (see there).
  S32 becomes N32 (ie. the ARM9 does NOT support fast sequential timing).
</PRE></TD></TR></TBODY></TABLE>That N32 is having same timing as normal N32 
access on NDS7, plus 3 waits.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Eg. an ARM9 N32 or S32 to 16bit bus will take: N16 + S16 + 3 waits.
  Eg. an ARM9 N32 or S32 to 32bit bus will take: N32 + 3 waits.
</PRE></TD></TR></TBODY></TABLE>Main Memory is ALWAYS having the nonsequential 3 
wait PENALTY (even on ARM7).<BR>*********************<BR>ARM9 Data fetches 
however are allowed to use sequential timing, as well as raw 16bit accesses 
(which aren't forcefully expanded to slow 32bit accesses).<BR>Nethertheless, the 
3 wait PENALTY is added to any NONSEQUENTIAL accesses.<BR>Only exceptions are 
cache and tcm which do not have that penalty.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Eg. LDRH on 16bit-data-bus is N16+3waits.
 Eg. LDR  on 16bit-data-bus is N16+S16+3waits.
 Eg. LDM  on 16bit-data-bus is N16+(n*2-1)*S16+3waits.
</PRE></TD></TR></TBODY></TABLE>Eventually, data fetches can take place parallel 
with opcode fetches.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> That is NOT true for LDM (works only for LDR/LDRB/LDRH).
 That is NOT true for DATA in SAME memory region than CODE.
 That is NOT true for DATA in ITCM (no matter if CODE is in ITCM).
</PRE></TD></TR></TBODY></TABLE>*********************<BR><BR><B>NDS9 
Busses</B><BR>Unlike ARM7, the ARM9 has separate code and data busses, allowing 
it to perform code and data fetches simultaneously (provided that both are in 
different memory regions).<BR>Normally, opcode execution times are calculated as 
"(codetime+datatime)", with the two busses, it can (ideally) be 
"MAX(codetime,datatime)", so the data access time may virtually take "NULL" 
clock cycles.<BR>In practice, DTCM and Data Cache access can take NULL cycles 
(however, data access to ITCM can't).<BR>When executing code in cache/itcm, data 
access to non-cache/tcm won't be any faster than with only one bus (as it's 
best, it could subtract 0.5 cycles from datatime, but, the access must be 
"aligned" to the bus-clock, so the "datatime-0.5" will be rounded back to the 
original "datatime").<BR>When executing code in uncached main ram, and accessing 
data (elsewhere than in main memory, cache/tcm), then execution time is 
typically "codetime+datatime-2".<BR><BR><B>NDS9 Internal 
Cycles</B><BR>Additionally to codetime+datatime, some opcodes include one or 
more internal cycles. Compared with ARM7, the behaviour of that internal cycles 
is slightly different on ARM9. First of, on the NDS9, the internal cycles are of 
course "half" cycles (ie. counted in 66MHz units, not in 33MHz units) (although 
they may get rounded to "full" cycles upon next memory access outside 
tcm/cache). And, the ARM9 is in some cases "skipping" the internal cycles, that 
often depending on whether or not the next opcode is using the result of the 
current opcode.<BR>Another big difference is that the ARM9 has lost the 
fast-multiply feature for small numbers; in some cases that may result in faster 
execution, but may also result in slower execution (one workaround would be to 
manually replace MUL opcodes by the new ARM9 halfword multiply opcodes); the 
slowest case are MUL opcodes that do update flags (eg. MULS, MLAS, SMULLS, etc. 
in ARM mode, and all ALL multiply opcodes in THUMB mode).<BR><BR><B>NDS9 Thumb 
Code</B><BR>In thumb mode, the NDS9 is fetching two 16bit opcodes by a single 
32bit read. In case of 32bit bus, this reduces the amount of memory traffic and 
may result in faster execution time, of course that works only if the two 
opcodes are within a word-aligned region (eg. loops at word-aligned addresses 
will be faster than non-aligned loops). However, the double-opcode-fetching is 
also done on 16bit bus memory, including for un-neccessary fetches, such like 
opcodes after branch commands, so the feature may cause heavy 
slowdowns.<BR><BR><B>Main Memory</B><BR>Reportedly, the main memory access times 
would be 5 cycles (nonsequential read), 4 cycles (nonsequential write), and 1 
cycle (sequential read or write). Plus whatever termination cycles. Plus 3 
cycles on nonsequential access to the last 2-bytes of a 32-byte block.<BR>That's 
of course all wrong. Reads are much slower than 5 cycles. Not yet tested if 
writes are faster. And, I haven't been able to reproduce the 3 cycles on last 
2-bytes effect, actually, it looks more as if that 3 cycles are accidently added 
to ALL nonsequential accesses, at ALL main memory addresses, and even to most 
OTHER memory regions... which might be the source of the PENALTY which occurs on 
VRAM/WRAM/OAM/Palette and I/O accesses.<BR><BR><B>DMA</B><BR>In some cases DMA 
main memory read cycles are reportedly performed simultaneously with DMA write 
cycles to other memory.<BR><BR><B>NDS9</B><BR>On the NDS9, all external memory 
access (and I/O) is delayed to bus clock (or actually MUCH slower due to the 
massive waitstates), so the full 66MHz can be used only internally in the NDS9 
CPU core, ie. with cache and TCM.<BR><BR><B>Bus Clock</B><BR>The exact bus clock 
is specified as 33.513982 MHz (1FF61FEh Hertz). However, on my own NDS, measured 
in relation to the RTC seconds IRQ, it appears more like 1FF6231h, that 
inaccuary of 1 cycle per 657138 cycles (about one second per week) on either 
oscillator, isn't too significant though.<BR><BR><B>GBA Slot</B><BR>The access 
time for GBA slot can be configured via EXMEMCNT register.<BR><BR><B>VRAM 
Waitstates</B><BR>Additionally, on NDS9, a one cycle wait can be added to VRAM 
accesses (when the video controller simultaneously accesses it) (that can be 
disabled by Forced Blank, see DISPCNT.Bit7). Moreover, additional VRAM 
waitstates occur when using the video capture function.<BR>Note: VRAM being 
mapped to NDS7 is always free of additional waits.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideo></A><FONT size=+2>&nbsp;DS 
Video</FONT></TD></TR></TBODY></TABLE><BR>The NDS has two 2D Video Engines, each 
basically the same as in GBA, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbalcdvideocontroller">GBA LCD Video 
Controller</A><BR><BR><B>NDS Specific 2D Video Features</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideostuff">DS Video Stuff</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideobgmodescontrol">DS Video BG 
Modes / Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideoobjs">DS Video OBJs</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideoextendedpalettes">DS Video 
Extended Palettes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideocaptureandmainmemorydisplaymode">DS 
Video Capture and Main Memory Display Mode</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideodisplaysystemblockdiagram">DS 
Video Display System Block Diagram</A><BR><BR>For Display Power Control (and 
Display Swap), and VRAM Allocation, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dspowermanagement">DS Power 
Management</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolvram">DS Memory Control 
- VRAM</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideostuff></A><FONT size=+2>&nbsp;DS Video 
  Stuff</FONT></TD></TR></TBODY></TABLE><BR><B>DS Display Dimensions / 
Timings</B><BR>Dot clock = 5.585664 MHz (=33.513982 MHz / 6)<BR>H-Timing: 256 
dots visible, 99 dots blanking, 355 dots total (15.7343KHz)<BR>V-Timing: 192 
lines visible, 71 lines blanking, 263 lines total (59.8261 Hz)<BR>The V-Blank 
cycle for the 3D Engine consists of the 23 lines, 191..213.<BR>Screen size 
62.5mm x 47.0mm (each) (256x192 pixels)<BR>Vertical space between screens 22mm 
(equivalent to 90 pixels)<BR><BR><B>400006Ch - NDS9 - MASTER_BRIGHT - 16bit - 
Master Brightness Up/Down</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   Factor used for 6bit R,G,B Intensities (0-16, values &gt;16 same as 16)
          Brightness up:   New = Old + (63-Old) * Factor/16
          Brightness down: New = Old - Old      * Factor/16
  5-13  Not used
  14-15 Mode (0=Disable, 1=Up, 2=Down, 3=Reserved)
</PRE></TD></TR></TBODY></TABLE><BR><B>DISPSTAT/VCOUNT</B><BR>The LY and LYC 
values are in range 0..262, so LY/LYC values have been expanded to 9bit values: 
LY = VCOUNT Bit 0..8, and LYC=DISPSTAT Bit8..15,7.<BR>VCOUNT register is 
write-able, allowing to synchronize linked DS consoles.<BR>For proper 
synchronization:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  write new LY values only in range of 202..212
  write only while old LY values are in range of 202..212
</PRE></TD></TR></TBODY></TABLE>DISPSTAT/VCOUNT supported by NDS9 (Engine A 
Ports, without separate Engine B Ports), and by NDS7 (allowing to synchronize 
NDS7 with display timings).<BR>Similar as on GBA, the VBlank flag isn't set in 
the last line (ie. only in lines 192..261, but not in line 262).<BR>Although the 
drawing time is only 1536 cycles (256*6), the NDS9 H-Blank flag is "0" for a 
total of 1606 cycles (and, for whatever reason, a bit longer, 1613 cycles in 
total, on NDS7).<BR><BR><B>VRAM Waitstates</B><BR>The display controller 
performs VRAM-reads once every 6 clock cycles, a 1 cycle waitstate is generated 
if the CPU simultaneously accesses VRAM. With capture enabled, additionally 
VRAM-writes take place once every 6 cycles, so the total VRAM-read/write access 
rate is then once every 3 cycles.<BR><BR><B>DS Window Glitches</B><BR>The DS 
counts scanlines in range 0..262 (0..106h), of which only the lower 8bit are 
compared with the WIN0V/WIN1V register settings. Respectively, Y1 coordinates 
00h..06h will be triggered in scanlines 100h-106h by mistake. That means, the 
window gets activated within VBlank period, and will be active in scanline 0 and 
up (that is no problem with Y1=0, but Y1=1..6 will appear as if if Y1 would be 
0). Workaround would be to disable the Window during VBlank, or to change Y1 
during VBlank (to a value that does not occur during VBlank period, ie. 
7..191).<BR>Also, there's a problem to fit the 256 pixel horizontal screen 
resolution into 8bit values: X1=00h is treated as 0 (left-most), X2=00h is 
treated as 100h (right-most). However, the window is not displayed if X1=X2=00h; 
the window width can be max 255 pixels.<BR><BR><B>2D Engines</B><BR>Includes two 
2D Engines, called A and B. Both engines are accessed by the ARM9 processor, 
each using different memory and register addresses:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Region______Engine A______________Engine B___________
  I/O Ports   4000000h              4001000h
  Palette     5000000h (1K)         5000400h (1K)
  BG VRAM     6000000h (max 512K)   6200000h (max 128K)
  OBJ VRAM    6400000h (max 256K)   6600000h (max 128K)
  OAM         7000000h (1K)         7000400h (1K)
</PRE></TD></TR></TBODY></TABLE>Engine A additionally supports 3D and 
large-screen 256-color Bitmaps, plus main-memory-display and vram-display modes, 
plus capture unit.<BR><BR><B>Viewing Angles</B><BR>The LCD screens are best 
viewed at viewing angles of 90 degrees. Colors may appear distorted, and may 
even become invisible at other viewing angles.<BR>When the console is handheld, 
both screens can be turned into preferred direction. When the console is settled 
on a table, only the upper screen can be turned, but the lower screen is stuck 
into horizontal position - which results rather bad visibility (unless the user 
moves his/her head directly above of it).<BR><BR><B>4000070h - NDS9 - TVOUTCNT - 
Unknown (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-3  "COMMAND"  (?)
  Bit4-7  "COMMAND2" (?)
  Bit8-11 "COMMAND3" (?)
</PRE></TD></TR></TBODY></TABLE>This register has been mentioned in an early I/O 
map from Nintendo, as far as I know, the register isn't used by any 
games/firmware/bios, not sure if it does really exist on release-version, or if 
it's been prototype stuff...?<BR><BR><B>DS-Lite Screens</B><BR>The screens in 
the DS-Lite seem to allow a wider range of vertical angles.<BR>The bad news is 
that the colors of the DS-Lite are (no surprise) not backwards compatible with 
older NDS and GBA displays. The good news is that Nintendo has finally reached 
near-CRT-quality (without blurred colors), so one could hope that they won't 
show up with more displays with other colors in future.<BR>Don't know if there's 
an official/recommended way to detect DS-Lite displays (?) possible methods 
would be whatever values in Firmware header, or by functionality of Power 
Managment device, or (not too LCD-related) by Wifi Chip ID.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideobgmodescontrol></A><FONT size=+2>&nbsp;DS Video BG 
      Modes / Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000000h - NDS9 - 
DISPCNT</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Engine Expl.
  0-2   A+B   BG Mode
  3     A     BG0 2D/3D Selection (instead CGB Mode) (0=2D, 1=3D)
  4     A+B   Tile OBJ Mapping        (0=2D; max 32KB, 1=1D; max 32KB..256KB)
  5     A+B   Bitmap OBJ 2D-Dimension (0=128x512 dots, 1=256x256 dots)
  6     A+B   Bitmap OBJ Mapping      (0=2D; max 128KB, 1=1D; max 128KB..256KB)
  7-15  A+B   Same as GBA
  16-17 A+B   Display Mode (Engine A: 0..3, Engine B: 0..1, GBA: Green Swap)
  18-19 A     VRAM block (0..3=VRAM A..D) (For Capture &amp; above Display Mode=2)
  20-21 A+B   Tile OBJ 1D-Boundary   (see Bit4)
  22    A     Bitmap OBJ 1D-Boundary (see Bit5-6)
  23    A+B   OBJ Processing during H-Blank (was located in Bit5 on GBA)
  24-26 A     Character Base (in 64K steps) (merged with 16K step in BGxCNT)
  27-29 A     Screen Base (in 64K steps) (merged with 2K step in BGxCNT)
  30    A+B   BG Extended Palettes   (0=Disable, 1=Enable)
  31    A+B   OBJ Extended Palettes  (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE><BR><B>BG Mode</B><BR>Engine A BG Mode (DISPCNT 
LSBs) (0-6, 7=Reserved)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Mode  BG0      BG1      BG2      BG3
  0     Text/3D  Text     Text     Text
  1     Text/3D  Text     Text     Affine
  2     Text/3D  Text     Affine   Affine
  3     Text/3D  Text     Text     Extended
  4     Text/3D  Text     Affine   Extended
  5     Text/3D  Text     Extended Extended
  6     3D       -        Large    -
</PRE></TD></TR></TBODY></TABLE>Of which, the "Extended" modes are sub-selected 
by BGxCNT bits:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  BGxCNT.Bit7 BGxCNT.Bit2 Extended Affine Mode Selection
  0           CharBaseLsb rot/scal with 16bit bgmap entries (Text+Affine mixup)
  1           0           rot/scal 256 color bitmap
  1           1           rot/scal direct color bitmap
</PRE></TD></TR></TBODY></TABLE>Engine B: Same as above, except that: Mode 6 is 
reserved (no Large screen bitmap), and BG0 is always Text (no 3D 
support).<BR>Affine = formerly Rot/Scal mode (with 8bit BG Map entries)<BR>Large 
Screen Bitmap = rot/scal 256 color bitmap (using all 512K of 2D 
VRAM)<BR><BR><B>Display Mode (DISPCNT.16-17):</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  Display off (screen becomes white)
  1  Graphics Display (normal BG and OBJ layers)
  2  Engine A only: VRAM Display (Bitmap from block selected in DISPCNT.18-19)
  3  Engine A only: Main Memory Display (Bitmap DMA transfer from Main RAM)
</PRE></TD></TR></TBODY></TABLE>Mode 2-3 display a raw direct color bitmap 
(15bit RGB values, the upper bit in each halfword is unused), without any 
further BG,OBJ,3D layers, these modes are completely bypassing the 2D/3D engines 
as well as any 2D effects, however the Master Brightness effect can be applied 
to these modes. Mode 2 is particulary useful to display captured 2D/3D images 
(in that case it can indirectly use the 2D/3D 
engine).<BR><BR><B>BGxCNT</B><BR>character base extended from bit2-3 to bit2-5 
(bit4-5 formerly unused)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  engine A screen base: BGxCNT.bits*2K + DISPCNT.bits*64K
  engine B screen base: BGxCNT.bits*2K + 0
  engine A char base: BGxCNT.bits*16K + DISPCNT.bits*64K
  engine B char base: BGxCNT.bits*16K + 0
</PRE></TD></TR></TBODY></TABLE>char base is used only in tile/map modes (not 
bitmap modes)<BR>screen base is used in tile/map modes,<BR>screen base used in 
bitmap modes as BGxCNT.bits*16K, without DISPCNT.bits*64K<BR>screen base however 
NOT used at all for Large screen bitmap mode<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  bgcnt size  text     rotscal    bitmap   large bmp
  0           256x256  128x128    128x128  512x1024
  1           512x256  256x256    256x256  1024x512
  2           256x512  512x512    512x256  -
  3           512x512  1024x1024  512x512  -
</PRE></TD></TR></TBODY></TABLE>bitmaps that require more than 128K VRAM are 
supported on engine A only.<BR><BR>For BGxCNT.Bit7 and BGxCNT.Bit2 in Extended 
Affine modes, see above BG Mode description (extended affine doesn't include 
16-color modes, so color depth bit can be used for mode selection. Also, bitmap 
modes do not use charbase, so charbase.0 can be used for mode selection as 
well).<BR><BR>for BG0, BG1 only: bit13 selects extended palette slot<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                   (BG0: 0=Slot0, 1=Slot2, BG1: 0=Slot1, 1=Slot3)
</PRE></TD></TR></TBODY></TABLE><BR>Direct Color Bitmap BG, and Direct Color 
Bitmap OBJ<BR>BG/OBJ Supports 32K colors (15bit RGB value) - so far same as GBAs 
BG.<BR>However, the upper bit (Bit15) is used as Alpha flag. That is, 
Alpha=0=Transparent, Alpha=1=Normal (ie. on the NDS, Direct Color values 
0..7FFFh are NOT displayed).<BR><BR>Unlike GBA bitmap modes, NDS bitmap modes 
are supporting the Area Overflow bit (BG2CNT and BG3CNT, Bit 13).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideoobjs></A><FONT size=+2>&nbsp;DS Video 
  OBJs</FONT></TD></TR></TBODY></TABLE><BR><B>DS OBJ Priority</B><BR>The GBA has 
been assigning OBJ priority in respect to the 7bit OAM entry number, regardless 
of the OBJs 2bit BG-priority attribute (which allowed to specify invalid 
priority orders). That problem has been fixed in DS mode by combining the above 
two values into a 9bit priority value.<BR><BR><B>OBJ Tile Mapping 
(DISPCNT.4,20-21):</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit4  Bit20-21  Dimension Boundary Total ;Notes
  0     x         2D        32       32K   ;Same as GBA 2D Mapping
  1     0         1D        32       32K   ;Same as GBA 1D Mapping
  1     1         1D        64       64K
  1     2         1D        128      128K
  1     3         1D        256      256K  ;Engine B: 128K max
</PRE></TD></TR></TBODY></TABLE>TileVramAddress = TileNumber * 
BoundaryValue<BR>Even if the boundary gets changed, OBJs are kept composed of 
8x8 tiles.<BR><BR><B>Bitmap OBJ Mapping (DISPCNT.6,5,22):</B><BR>Bitmap OBJs are 
15bit Direct Color data, plus 1bit Alpha flag (in bit15).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit6 Bit5 Bit22 Dimension    Boundary   Total ;Notes
  0    0    x     2D/128 dots  8x8 dots   128K  ;Source Bitmap width 128 dots
  0    1    x     2D/256 dots  8x8 dots   128K  ;Source Bitmap width 256 dots
  1    0    0     1D           128 bytes  128K  ;Source Width = Target Width
  1    0    1     1D           256 bytes  256K  ;Engine A only
  1    1    x     Reserved
</PRE></TD></TR></TBODY></TABLE>In 1D mapping mode, the Tile Number is simply 
multiplied by the boundary value.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1D_BitmapVramAddress = TileNumber(0..3FFh) * BoundaryValue(128..256)
  2D_BitmapVramAddress = (TileNo AND MaskX)*10h + (TileNo AND NOT MaskX)*80h
</PRE></TD></TR></TBODY></TABLE>In 2D mode, the Tile Number is split into X and 
Y indices, the X index is located in the LSBs (ie. MaskX=0Fh, or MaskX=1Fh, 
depending on DISPCNT.5).<BR><BR><B>OBJ Attribute 0 and 2</B><BR>Setting the OBJ 
Mode bits (Attr 0, Bit10-11) to a value of 3 has been prohibited in GBA, 
however, in NDS it selects the the new Bitmap OBJ mode; in that mode, the Color 
depth bit (Attr 0, Bit13) should be set to zero; also in that mode, the color 
bits (Attr 2, Bit 12-15) are used as Alpha-OAM value (instead of as palette 
setting).<BR><BR><B>OBJ Vertical Wrap</B><BR>On the GBA, a large OBJ (with 64pix 
height, scaled into double-size region of 128pix height) located near the bottom 
of the screen has been wrapped to the top of the screen (and was NOT displayed 
at the bottom of the screen).<BR>This problem has been "corrected" in the NDS 
(except in GBA mode), that is, on the NDS, the OBJ appears BOTH at the top and 
bottom of the screen. That isn't necessarily better - the advantage is that one 
can manually enable/disable the OBJ in the desired screen-half on IRQ level; 
that'd be required only if the wrapped portion is non-transparent.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideoextendedpalettes></A><FONT size=+2>&nbsp;DS Video 
      Extended Palettes</FONT></TD></TR></TBODY></TABLE><BR><B>Extended 
Palettes</B><BR>When allocating extended palettes, the allocated memory is not 
mapped to the CPU bus, so the CPU can access extended palette only when 
temporarily de-allocating it.<BR><BR>Color 0 of all standard/extended palettes 
is transparent, color 0 of BG standard palette 0 is used as backdrop. extended 
palette memory must be allocated to VRAM.<BR><BR>BG Extended Palette enabled in 
DISPCNT Bit 30, when enabled,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> standard palette --&gt; 16-color tiles (with 16bit bgmap entries) (text)
                      256-color tiles (with 8bit bgmap entries) (rot/scal)
                      256-color bitmaps
                      backdrop-color (color 0)
 extended palette --&gt; 256-color tiles (with 16bit bgmap entries)(text,rot/scal)
</PRE></TD></TR></TBODY></TABLE>Allocated VRAM is split into 4 slots of 8K each 
(32K used in total), normally BG0..3 are using Slot 0..3, however BG0 and BG1 
can be optionally changed to BG0=Slot2, and BG1=Slot3 via BG0CNT and 
BG1CNT.<BR><BR>OBJ Extended Palette enabled in DISPCNT Bit 31, when enabled,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> 16 colors x 16 palettes --&gt; standard palette memory (=256 colors)
 256 colors x 16 palettes --&gt; extended palette memory (=4096 colors)
</PRE></TD></TR></TBODY></TABLE>Extended OBJ palette memory must be allocated to 
VRAM F, G, or I (which are 16K) of which only the first 8K are used for extended 
palettes (=1000h 16bit entries).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideocaptureandmainmemorydisplaymode></A><FONT 
      size=+2>&nbsp;DS Video Capture and Main Memory Display 
  Mode</FONT></TD></TR></TBODY></TABLE><BR><B>4000064h - NDS9 - DISPCAPCNT - 32bit 
- Display Capture Control Register (R/W)</B><BR>Capture is supported for Display 
Engine A only.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   EVA               (0..16 = Blending Factor for Source A)
  5-7   Not used
  8-12  EVB               (0..16 = Blending Factor for Source B)
  13-15 Not used
  16-17 VRAM Write Block  (0..3 = VRAM A..D) (VRAM must be allocated to LCDC)
  18-19 VRAM Write Offset (0=00000h, 0=08000h, 0=10000h, 0=18000h)
  20-21 Capture Size      (0=128x128, 1=256x64, 2=256x128, 3=256x192 dots)
  22-23 Not used
  24    Source A          (0=Graphics Screen BG+3D+OBJ, 1=3D Screen)
  25    Source B          (0=VRAM, 1=Main Memory Display FIFO)
  26-27 VRAM Read Offset  (0=00000h, 0=08000h, 0=10000h, 0=18000h)
  28    Not used
  29-30 Capture Source    (0=Source A, 1=Source B, 2/3=Sources A+B blended)
  31    Capture Enable    (0=Disable/Ready, 1=Enable/Busy)
</PRE></TD></TR></TBODY></TABLE>Notes:<BR>VRAM Read Block (VRAM A..D) is 
selected in DISPCNT Bits 18-19.<BR>VRAM Read Block can be (or must be ?) 
allocated to LCDC (MST=0).<BR>VRAM Read Offset is ignored (zero) in VRAM Display 
Mode (DISPCNT.16-17).<BR>VRAM Read/Write Offsets wrap to 00000h when exceeding 
1FFFFh (max 128K).<BR>Capture Sizes less than 256x192 capture the upper-left 
portion of the screen.<BR>Blending factors EVA and EVB are used only if "Source 
A+B blended" selected.<BR>After setting the Capture Enable bit, capture starts 
at next line 0, and the capture enable/busy bit is then automatically cleared 
(in line 192, regardless of the capture size).<BR><BR>Capture data is 15bit 
color depth (even when capturing 18bit 3D-images).<BR>Capture A: Dest_Intensity 
= SrcA_Intensitity ; Dest_Alpha=SrcA_Alpha.<BR>Capture B: Dest_Intensity = 
SrcB_Intensitity ; Dest_Alpha=SrcB_Alpha.<BR>Capture A+B (blending):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> Dest_Intensity = (  (SrcA_Intensitity * SrcA_Alpha * EVA)
                   + (SrcB_Intensitity * SrcB_Alpha * EVB) ) / 16
 Dest_Alpha = (SrcA_Alpha AND (EVA&gt;0)) OR (SrcB_Alpha AND EVB&gt;0))
</PRE></TD></TR></TBODY></TABLE><BR>Capture provides a couple of interesting 
effects.<BR>For example, 3D Engine output can be captured via source A (to 
LCDC-allocated VRAM), in the next frame, either Graphics Engine A or B can 
display the captured 3D image in VRAM image as BG2, BG3, or OBJ (from 
BG/OBJ-allocated VRAM); this method requires to switch between LCDC- and 
BG/OBJ-allocation.<BR>Another example would be to capture Engine A output, the 
captured image can be displayed (via VRAM Display mode) in the following frames, 
simultaneously the new Engine A output can be captured, blended with the old 
captured image; in that mode moved objects will leave traces on the screen; this 
method works with a single LCDC-allocated VRAM block.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsvideodisplaysystemblockdiagram">DS 
Video Display System Block Diagram</A><BR><BR><B>4000068h - NDS9 - 
DISP_MMEM_FIFO - 32bit - Main Memory Display FIFO (R?/W)</B><BR>Intended to send 
256x192 pixel 32K color bitmaps by DMA directly<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> - to Screen A             (set DISPCNT to Main Memory Display mode), or
 - to Display Capture unit (set DISPCAPCNT to Main Memory Source).
</PRE></TD></TR></TBODY></TABLE>The FIFO can receive 4 words (8 pixels) at a 
time, each pixel is a 15bit RGB value (the upper bit, bit15, is unused).<BR>Set 
DMA to Main Memory mode, 32bit transfer width, word count set to 4, destination 
address to DISP_MMEM_FIFO, source address must be in Main Memory.<BR>Transfer 
starts at next frame.<BR>Main Memory Display/Capture is supported for Display 
Engine A only.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsvideodisplaysystemblockdiagram></A><FONT size=+2>&nbsp;DS 
      Video Display System Block Diagram</FONT></TD></TR></TBODY></TABLE>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>             _____________               __________
  VRAM A --&gt;| 2D Graphics |--------OBJ-&gt;|          |
  VRAM B --&gt;| Engine A    |--------BG3-&gt;| Layering |
  VRAM C --&gt;|             |--------BG2-&gt;| and      |
  VRAM D --&gt;|             |--------BG1-&gt;| Special  |
  VRAM E --&gt;|             |   ___       | Effects  |
  VRAM F --&gt;|             |-&gt;|SEL|      |          |          ______
  VRAM G --&gt;| - - - - - - |  |BG0|-BG0-&gt;|          |----+---&gt;|      |
            | 3D Graphics |-&gt;|___|      |__________|    |    |Select|
            | Engine      |                             |    |Video |
            |_____________|--------3D----------------+  |    |Input |
             _______      _______              ___   |  |    |      |
            |       |    |       |&lt;-----------|SEL|&lt;-+  |    |and   |--&gt;
            |       |    |       |    _____   |A  |     |    |      |
  VRAM A &lt;--|Select |    |Select |   |     |&lt;-|___|&lt;----+    |Master|
  VRAM B &lt;--|Capture|&lt;---|Capture|&lt;--|Blend|   ___           |Bright|
  VRAM C &lt;--|Dest.  |    |Source |   |_____|&lt;-|SEL|&lt;----+    |A     |
  VRAM D &lt;--|       |    |       |            |B  |     |    |      |
            |_______|    |_______|&lt;-----------|___|&lt;-+  |    |      |
             _______                                 |  |    |      |
  VRAM A --&gt;|Select |                                |  |    |      |
  VRAM B --&gt;|Display|--------------------------------+------&gt;|      |
  VRAM C --&gt;|VRAM   |                                   |    |      |
  VRAM D --&gt;|_______|   _____________                   |    |      |
                       |Main Memory  |                  |    |      |
  Main   ------DMA----&gt;|Display FIFO |------------------+---&gt;|______|
  Memory               |_____________|
             _____________               __________           ______
  VRAM C --&gt;| 2D Graphics |--------OBJ-&gt;| Layering |         |      |
  VRAM D --&gt;| Engine B    |--------BG3-&gt;| and      |         |Master|
  VRAM H --&gt;|             |--------BG2-&gt;| Special  |--------&gt;|Bright|--&gt;
  VRAM I --&gt;|             |--------BG1-&gt;| Effects  |         |B     |
            |_____________|--------BG0-&gt;|__________|         |______|
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dvideo></A><FONT size=+2>&nbsp;DS 3D 
  Video</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3doverview">DS 3D Overview</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3diomap">DS 3D I/O Map</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3ddisplaycontrol">DS 3D Display 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dgeometrycommands">DS 3D Geometry 
Commands</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixloadmultiply">DS 3D Matrix 
Load/Multiply</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixtypes">DS 3D Matrix 
Types</A><BR><A href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixstack">DS 3D 
Matrix Stack</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixexamplesprojection">DS 3D 
Matrix Examples (Projection)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixexamplesrotatescaletranslate">DS 
3D Matrix Examples (Rotate/Scale/Translate)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dmatrixexamplesmathsbasics">DS 3D 
Matrix Examples (Maths Basics)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dpolygonattributes">DS 3D Polygon 
Attributes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dpolygondefinitionsbyvertices">DS 
3D Polygon Definitions by Vertices</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dpolygonlightparameters">DS 3D 
Polygon Light Parameters</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dshadowpolygons">DS 3D Shadow 
Polygons</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtextureattributes">DS 3D Texture 
Attributes</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtextureformats">DS 3D Texture 
Formats</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtexturecoordinates">DS 3D Texture 
Coordinates</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtextureblending">DS 3D Texture 
Blending</A><BR><A href="http://nocash.emubase.de/gbatek.htm#ds3dtoonedgefog">DS 
3D Toon, Edge, Fog</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dstatus">DS 3D Status</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtests">DS 3D Tests</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3drearplane">DS 3D 
Rear-Plane</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dfinal2doutput">DS 3D Final 2D 
Output</A><BR><BR>3D is more or less (about 90%) understood and 
described.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3doverview></A><FONT size=+2>&nbsp;DS 3D 
  Overview</FONT></TD></TR></TBODY></TABLE><BR>The NDS 3D hardware consists of a 
Geometry Engine, and a Rendering Engine.<BR><BR><B>Geometry Engine (Precalculate 
coordinates &amp; assign polygon attributes)</B><BR>Geometry commands can be 
sent via Ports 4000440h and up (or alternately, written directly to Port 
4000400h).<BR>The commands include matrix and vector multiplications, the 
purpose is to rotate/scale/translate coordinates (vertices), the resulting 
coordinates are stored in Vertex RAM.<BR>Moreover, it allows to assign 
attributes to the polygons and vertices, that includes vertex colors (or 
automatically calculated light colors), texture attributes, number of vertices 
per polygon (three or four), and a number of flags, these attributes are stored 
in Polygon RAM. Polygon RAM also contains pointers to the corresponding vertices 
in Vertex RAM.<BR><BR><B>Swap Buffers (Pass data from the Geometry Engine to the 
Rendering Engine)</B><BR>The hardware includes two sets of Vertex/Polygon RAM, 
one used by the Geometry Engine, one by the Rendering Engine. The Swap Buffers 
command simply exchanges these buffers (so the new Geometry Data is passed to 
the Rendering Engine) (and the old buffer is emptied, so the Geometry engine can 
write new data to it).<BR>Aside from that buffers, it does probably also have 
TWO sets of per-frame control registers? Namely those at Port 
4000060h..40003BFh. If there are TWO sets, then these registers probably also 
swapped (or more probably: copied) upon Swap Buffers command?<BR>Except, one 
thing: Swap Buffers obviously can't swap Texture memory (so software must take 
care that Texture memory is kept mapped throughout 
rendering).<BR><BR><B>Rendering Engine (Display Output)</B><BR>The Rendering 
Engine draws the various Polygons, and outputs them as BG0 layer to the 2D Video 
controller (which may then output them to the screen, or to the video capture 
unit). The Rendering part is done automatically by hardware, so the software has 
little influence on it.<BR>Rendering is done scanline-by-scanline, so there's 
only a limited number of clock cycles per scanline, which is limiting the 
maximum number of polygons per scanline. However, due to the 48-line cache (see 
below), some scanlines are allowed to exceed that maximum.<BR>Rendering starts 
48 lines in advance (while still in the Vblank period) (and does then continue 
throughout the whole display period), the rendered data is written to a small 
cache that can hold up to 48 scanlines.<BR><BR><B>Scanline Cache vs 
Framebuffer</B><BR>Note: There's only the 48-line cache (not a full 192-line 
framebuffer to store the whole rendered image). That is perfectly reasonable 
since animated data is normally drawn only once (so there would be no need to 
store it). That, assuming that the Geometry Engine presents new data every frame 
(otherwise, if the Geometry software is too slow, or if the image isn't 
animated, then the hardware is automatically rendering the same image again, and 
again).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3diomap></A><FONT size=+2>&nbsp;DS 3D I/O 
  Map</FONT></TD></TR></TBODY></TABLE><BR><B>3D I/O Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Address  Siz Name            Expl.
  4000060h 2   DISP3DCNT       3D Display Control Register (R/W)
  4000320h 1   RDLINES_COUNT   Rendered Line Count Register (R)
  4000330h 10h EDGE_COLOR      Edge Colors 0..7 (W)
  4000340h 1   ALPHA_TEST_REF  Alpha-Test Comparision Value (W)
  4000350h 4   CLEAR_COLOR     Clear Color Attribute Register (W)
  4000354h 2   CLEAR_DEPTH     Clear Depth Register (W)
  4000356h 2   CLRIMAGE_OFFSET Rear-plane Bitmap Scroll Offsets (W)
  4000358h 4   FOG_COLOR       Fog Color (W)
  400035Ch 2   FOG_OFFSET      Fog Offset (W)
  4000360h 20h FOG_TABLE       Fog Density Table, 32 entries (W)
  4000380h 40h TOON_TABLE      Toon Table, 32 colors (W)
  4000400h 40h GXFIFO          Geometry Command FIFO (W)
  4000440h ... ...             Geometry Command Ports (see below)
  4000600h 4   GXSTAT          Geometry Engine Status Register (R and R/W)
  4000604h 4   RAM_COUNT       Polygon List &amp; Vertex RAM Count Register (R)
  4000610h 2   DISP_1DOT_DEPTH 1-Dot Polygon Display Boundary Depth (W)
  4000620h 10h POS_RESULT      Position Test Results (R)
  4000630h 6   VEC_RESULT      Vector Test Results (R)
  4000640h 40h CLIPMTX_RESULT  Read Current Clip Coordinates Matrix (R)
  4000680h 24h VECMTX_RESULT   Read Current Directional Vector Matrix (R)
</PRE></TD></TR></TBODY></TABLE><BR><B>Geometry Commands (can be invoked by Port 
Address, or by Command ID)</B><BR>Table shows Port Address, Command ID, Number 
of Parameters, and Clock Cycles.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Address  Cmd Pa.Cy.
  N/A      00h -  -   NOP - No Operation (for padding packed GXFIFO commands)
  4000440h 10h 1  1   MTX_MODE - Set Matrix Mode (W)
  4000444h 11h -  17  MTX_PUSH - Push Current Matrix on Stack (W)
  4000448h 12h 1  36  MTX_POP - Pop Current Matrix from Stack (W)
  400044Ch 13h 1  17  MTX_STORE - Store Current Matrix on Stack (W)
  4000450h 14h 1  36  MTX_RESTORE - Restore Current Matrix from Stack (W)
  4000454h 15h -  19  MTX_IDENTITY - Load Unit Matrix to Current Matrix (W)
  4000458h 16h 16 34  MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)
  400045Ch 17h 12 30  MTX_LOAD_4x3 - Load 4x3 Matrix to Current Matrix (W)
  4000460h 18h 16 35* MTX_MULT_4x4 - Multiply Current Matrix by 4x4 Matrix (W)
  4000464h 19h 12 31* MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)
  4000468h 1Ah 9  28* MTX_MULT_3x3 - Multiply Current Matrix by 3x3 Matrix (W)
  400046Ch 1Bh 3  22  MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)
  4000470h 1Ch 3  22* MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W)
  4000480h 20h 1  1   COLOR - Directly Set Vertex Color (W)
  4000484h 21h 1  9*  NORMAL - Set Normal Vector (W)
  4000488h 22h 1  1   TEXCOORD - Set Texture Coordinates (W)
  400048Ch 23h 2  9   VTX_16 - Set Vertex XYZ Coordinates (W)
  4000490h 24h 1  8   VTX_10 - Set Vertex XYZ Coordinates (W)
  4000494h 25h 1  8   VTX_XY - Set Vertex XY Coordinates (W)
  4000498h 26h 1  8   VTX_XZ - Set Vertex XZ Coordinates (W)
  400049Ch 27h 1  8   VTX_YZ - Set Vertex YZ Coordinates (W)
  40004A0h 28h 1  8   VTX_DIFF - Set Relative Vertex Coordinates (W)
  40004A4h 29h 1  1   POLYGON_ATTR - Set Polygon Attributes (W)
  40004A8h 2Ah 1  1   TEXIMAGE_PARAM - Set Texture Parameters (W)
  40004ACh 2Bh 1  1   PLTT_BASE - Set Texture Palette Base Address (W)
  40004C0h 30h 1  4   DIF_AMB - MaterialColor0 - Diffuse/Ambient Reflect. (W)
  40004C4h 31h 1  4   SPE_EMI - MaterialColor1 - Specular Ref. &amp; Emission (W)
  40004C8h 32h 1  6   LIGHT_VECTOR - Set Light's Directional Vector (W)
  40004CCh 33h 1  1   LIGHT_COLOR - Set Light Color (W)
  40004D0h 34h 32 32  SHININESS - Specular Reflection Shininess Table (W)
  4000500h 40h 1  1   BEGIN_VTXS - Start of Vertex List (W)
  4000504h 41h -  1   END_VTXS - End of Vertex List (W)
  4000540h 50h 1  392 SWAP_BUFFERS - Swap Rendering Engine Buffer (W)
  4000580h 60h 1  1   VIEWPORT - Set Viewport (W)
  40005C0h 70h 3  103 BOX_TEST - Test if Cuboid Sits inside View Volume (W)
  40005C4h 71h 2  9   POS_TEST - Set Position Coordinates for Test (W)
  40005C8h 72h 1  5   VEC_TEST - Set Directional Vector for Test (W)
</PRE></TD></TR></TBODY></TABLE>All cycle timings are counted in 33.51MHz units. 
NORMAL commands takes 9..12 cycles, depending on the number of enabled lights in 
PolyAttr (Huh, 9..12 (four timings) cycles for 0..4 (five settings) lights?) 
Total execution time of SwapBuffers is Duration until VBlank, plus 392 
cycles.<BR>In MTX_MODE=2 (Simultanous Set), MTX_MULT/TRANS take additional 30 
cycles.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3ddisplaycontrol></A><FONT size=+2>&nbsp;DS 3D Display 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>4000060h - DISP3DCNT - 3D Display 
Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Texture Mapping     (0=Disable, 1=Enable)
  1     PolygonAttr Shading (0=Toon Shading, 1=Highlight Shading)
  2     Alpha-Test          (0=Disable, 1=Enable) (see ALPHA_TEST_REF)
  3     Alpha-Blending      (0=Disable, 1=Enable) (see various Alpha values)
  4     Anti-aliasing       (0=Disable, 1=Enable)
  5     Edge-marking        (0=Disable, 1=Enable) (see EDGE_COLOR)
  6     Fog Mode            (0=Alpha and Color, 1=Only Alpha) (see FOG_COLOR)
  7     Fog Master Enable   (0=Disable, 1=Enable)
  8-11  Fog Shift           (0..10; SHR-Divider) (see FOG_OFFSET)
  12    Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge)
  13    Polygon/Vertex RAM Overflow    (0=None, 1=Overflow/Acknowledge)
  14    Rear-Plane Mode                (0=Blank, 1=Bitmap)
  15-31 Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000540h - Cmd 50h - SWAP_BUFFERS - Swap 
Rendering Engine Buffer (W)</B><BR>SwapBuffers exchanges the two sets of 
Polygon/Vertex RAM buffers, that is, the newly defined polygons/vertices are 
passed to the rendering engine (and will be displayed in following frame(s)). 
The other buffer is emptied, and passed to the Geometry Engine (to be filled 
with new polygons/vertices by Geometry Commands).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Translucent polygon Y-sorting (0=Auto-sort, 1=Manual-sort)
  1     Depth Buffering  (0=With Z-value, 1=With W-value)
        (mode 1 does not function properly with orthogonal projections)
  2-31  Not used
</PRE></TD></TR></TBODY></TABLE>SwapBuffers isn't executed until next VBlank 
(Scanline 192) (the Geometry Engine is halted for that duration). SwapBuffers 
should not be issued within Begin/End.<BR>SwapBuffers does lock-up the 3D 
hardware if an incomplete polygon list has been defined (eg. a triangle with 
only 2 vertices). On lock-up, only 2D video is kept working, any wait-loops for 
GXSTAT.27 will hang the program. Once lock-up has occured, there seems to be no 
way to recover by software, not by sending the missing veric(es), and not even 
by pulsing POWCNT1.Bit2-3.<BR><BR><B>4000580h - Cmd 60h - VIEWPORT - Set 
Viewport (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Screen/BG0 Coordinate X1 (0..255) (For Fullscreen: 0=Left-most)
  8-15  Screen/BG0 Coordinate Y1 (0..191) (For Fullscreen: 0=Bottom-most)
  16-23 Screen/BG0 Coordinate X2 (0..255) (For Fullscreen: 255=Right-most)
  24-31 Screen/BG0 Coordinate Y2 (0..191) (For Fullscreen: 191=Top-most)
</PRE></TD></TR></TBODY></TABLE>Coordinate 0,0 is the lower-left (unlike for 2D 
where it'd be upper-left).<BR>The 3D view-volume (size as defined by the 
Projection Matrix) is automatically scaled to match into the Viewport area. 
Although polygon vertices are clipped to the view-volume, some vertices may 
still exceed to X2,Y1 (lower-right) boundary by one pixel, due to some sort of 
rounding errors. The Viewport settings don't affect the size or position of the 
3D Rear-Plane. Viewport should not be issued within 
Begin/End.<BR><BR><B>4000610h - DISP_1DOT_DEPTH - 1-Dot Polygon Display Boundary 
Depth (W)</B><BR>1-Dot Polygons are very small, or very distant polygons, which 
would be rendered as a single pixel on screen. Polygons with a depth value 
greater (more distant) than DISP_1DOT_DEPTH can be automatically hidden; in 
order to reduce memory consumption, or to reduce dirt on the screen.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-14  W-Coordinate (Unsigned, 12bit integer, 3bit fractional part)
  15-31 Not used     (0000h=Closest, 7FFFh=Most Distant)
</PRE></TD></TR></TBODY></TABLE>The DISP_1DOT_DEPTH comparision can be 
enabled/disabled per polygon, in POLYGON_ATTR.Bit13, so "important" polygons can 
be displayed regardless of their size and distance.<BR><BR><B>4000340h - 
ALPHA_TEST_REF - Alpha-Test Comparision Value (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   Alpha-Test Comparision Value (0..31) (Hide pixels if Alpha&lt;AlphaRef)
  5-31  Not used
</PRE></TD></TR></TBODY></TABLE>Alpha Test can be enabled in DISP3DCNT.Bit2, 
when enabled, pixels with Alpha values less than ALPHA_TEST_REF are not rendered 
(ie. their alpha value is forced to zero). Alpha Test is performed on the final 
polygon pixels (ie. after texture blending).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dgeometrycommands></A><FONT size=+2>&nbsp;DS 3D Geometry 
      Commands</FONT></TD></TR></TBODY></TABLE><BR><B>4000400h - GXFIFO - Geometry 
Command FIFO (W) (mirrored up to 400043Fh?)</B><BR>Used to send packed commands, 
unpacked commands,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   First  Packed Command (or Unpacked Command)
  8-15  Second Packed Command (or 00h=None)
  16-23 Third  Packed Command (or 00h=None)
  24-31 Fourth Packed Command (or 00h=None)
</PRE></TD></TR></TBODY></TABLE>and parameters,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-31  Parameter data for the previously sent (packed) command(s)
</PRE></TD></TR></TBODY></TABLE>to the Geometry engine.<BR><BR><B>FIFO / PIPE 
Number of Entries</B><BR>The FIFO has 256 entries, additionally, there is a PIPE 
with four entries (giving a total of 260 entries). If the FIFO is empty, and if 
the PIPE isn't full, then data is moved directly into the PIPE, otherwise it is 
moved into the FIFO. If the PIPE runs half empty (less than 3 entries) then 2 
entries are moved from the FIFO to the PIPE. The state of the FIFO can be 
obtained in GXSTAT.Bit16-26, observe that there may be still data in the PIPE, 
even if the FIFO is empty. Check the busy flag in GXSTAT.Bit27 to see if the 
PIPE or FIFO contains data (or if a command is still executing).<BR>Each 
PIPE/FIFO entry consists of 40bits of data (8bit command code, plus 32bit 
parameter value). Commands without parameters occupy 1 entry, and Commands with 
N parameters occupy N entries.<BR><BR><B>Sending Commands by Ports 
4000440h..40005FFh</B><BR>Geometry commands can be indirectly sent to the FIFO 
via ports 4000440h and up.<BR>For a command with N paramters: issue N writes to 
the port.<BR>For a command without parameters: ussue one dummy-write to the 
port.<BR>That mechanism puts the 8bit command + 32bit parameter into the 
FIFO/PIPE.<BR>If the FIFO is full, then a wait is generated until data is 
removed from the FIFO, ie. the STR opcode gets freezed, during the wait, the bus 
cannot be used even by DMA, interrupts, or by the NDS7 CPU.<BR><BR><B>GXFIFO 
Access via DMA</B><BR>Larger pre-calculated data blocks can be sent directly to 
the FIFO. This is usually done via DMA (use DMA in Geometry Command Mode, 32bit 
units, Dest=4000400h/fixed, Length=NumWords, Repeat=0). The timings are handled 
automatically, ie. the system (should) doesn't freeze when the FIFO is full (see 
below Overkill note though). DMA starts when the FIFO becomes less than half 
full, the DMA does then write 112 words to the GXFIFO register (or less, if the 
remaining DMA transfer length gets zero).<BR><BR><B>GXFIFO Access via 
STR,STRD,STM</B><BR>If desired, STR,STRD,STM opcodes can be used to write to the 
FIFO.<BR>Opcodes that write more than one 32bit value (ie. STRD and STM) can be 
used to send ONE UNPACKED command, plus any parameters which belong to that 
command. After that, there must be a 1 cycle delay before sending the next 
command (ie. one cannot sent more than one command at once with a single opcode, 
each command must be invoked by a new opcode). STRD and STM can be used because 
the GXFIFO register is mirrored to 4000400h..43Fh (16 words).<BR>As with Ports 
4000440h and up, the CPU gets stopped if (and as long as) the FIFO is 
full.<BR><BR><B>GXFIFO / Unpacked Commands</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  - command1 (upper 24bit zero)
  - parameter(s) for command1 (if any)
  - command2 (upper 24bit zero)
  - parameter(s) for command2 (if any)
  - command3 (upper 24bit zero)
  - parameter(s) for command3 (if any)
</PRE></TD></TR></TBODY></TABLE><BR><B>GXFIFO / Packed Commands</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  - command1,2,3,4 packed into one 32bit value (all bits used)
  - parameter(s) for command1 (if any)
  - parameter(s) for command2 (if any)
  - parameter(s) for command3 (if any)
  - parameter(s) for command4 (top-most packed command MUST have parameters)
  - command5,6 packed into one 32bit value (upper 16bit zero)
  - parameter(s) for command5 (if any)
  - parameter(s) for command6 (top-most packed command MUST have parameters)
  - command7,8,9 packed into one 32bit value (upper 8bit zero)
  - parameter(s) for command7 (if any)
  - parameter(s) for command8 (if any)
  - parameter(s) for command9 (top-most packed command MUST have parameters)
</PRE></TD></TR></TBODY></TABLE>Packed commands are first decompressed and then 
stored in command the FIFO.<BR><BR><B>GXFIFO DMA Overkill on Packed Commands 
Without Parameters</B><BR>Normally, the 112 word limit ensures that the FIFO 
(256 entries) doesn't get full, however, this limit is much too high for sending 
a lot of "Packed Commands Without Parameters" (ie. PUSH, IDENTITY, or END) - eg. 
sending 112 x Packed(00151515h) to GXFIFO would write 336 x Cmd(15h) to the 
FIFO, which is causing the FIFO to get full, and which is causing the DMA (and 
CPU) to be paused (for several seconds, in WORST case) until enough FIFO 
commands have been processed to allow the DMA to finish the 112 word 
transfer.<BR>Not sure if there's much chance to get Overkills in practice. 
Normally most commands DO have parameters, and so, usually even LESS than 112 
FIFO entries are occupied (since 8bit commands with 32bit parameters are merged 
into single 40bit FIFO entries).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixloadmultiply></A><FONT size=+2>&nbsp;DS 3D Matrix 
      Load/Multiply</FONT></TD></TR></TBODY></TABLE><BR><B>4000440h - Cmd 10h - 
MTX_MODE - Set Matrix Mode (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Matrix Mode (0..3)
         0  Projection Matrix
         1  Position Matrix (aka Modelview Matrix)
         2  Position &amp; Vector Simultaneous Set mode (used for Light+VEC_TEST)
         3  Texture Matrix (see DS 3D Texture Coordinates chapter)
  2-31  Not used
</PRE></TD></TR></TBODY></TABLE>Selects the current Matrix, all following MTX 
commands (load, multiply, push, pop, etc.) are applied to that matrix. In Mode 
2, all MTX commands are applied to both the Position and Vector matrices (except 
for MTX_SCALE which doesn't change the Vector Matrix, even in Mode 
2).<BR><BR><B>4000454h - Cmd 15h - MTX_IDENTITY - Load Unit Matrix to Current 
Matrix (W)</B><BR>Sets C=I. Parameters: None<BR>The Identity Matrix (I), aka 
Unit Matrix, consists of all zeroes, with a diagonal row of ones. A matrix 
multiplied by the Unit Matrix is left unchanged.<BR><BR><B>4000458h - Cmd 16h - 
MTX_LOAD_4x4 - Load 4x4 Matrix to Current Matrix (W)</B><BR>Sets C=M. 
Parameters: 16, m[0..15]<BR><BR><B>400045Ch - Cmd 17h - MTX_LOAD_4x3 - Load 4x3 
Matrix to Current Matrix (W)</B><BR>Sets C=M. Parameters: 12, 
m[0..11]<BR><BR><B>4000460h - Cmd 18h - MTX_MULT_4x4 - Multiply Current Matrix 
by 4x4 Matrix (W)</B><BR>Sets C=M*C. Parameters: 16, m[0..15]<BR><BR><B>4000464h 
- Cmd 19h - MTX_MULT_4x3 - Multiply Current Matrix by 4x3 Matrix (W)</B><BR>Sets 
C=M*C. Parameters: 12, m[0..11]<BR><BR><B>4000468h - Cmd 1Ah - MTX_MULT_3x3 - 
Multiply Current Matrix by 3x3 Matrix (W)</B><BR>Sets C=M*C. Parameters: 9, 
m[0..8]<BR><BR><B>400046Ch - Cmd 1Bh - MTX_SCALE - Multiply Current Matrix by 
Scale Matrix (W)</B><BR>Sets C=M*C. Parameters: 3, m[0..2] (MTX_SCALE doesn't 
change Vector Matrix)<BR><BR><B>4000470h - Cmd 1Ch - MTX_TRANS - Mult. Curr. 
Matrix by Translation Matrix (W)</B><BR>Sets C=M*C. Parameters: 3, m[0..2] 
(x,y,z position)<BR><BR><B>4000640h..67Fh - CLIPMTX_RESULT - Read Current Clip 
Coordinates Matrix (R)</B><BR>This 64-byte region (16 words) contains the 
m[0..15] values of the Current Clip Coordinates Matrix, arranged in 4x4 Matrix 
format. Make sure that the Geometry Engine is stopped (GXSTAT.27) before reading 
from these registers.<BR>The Clip Matrix is internally re-calculated anytime 
when changing the Position or Projection matrices: 
ClipMatrix=PositionMatrix*ProjectionMatrix, this matrix is internally used to 
convert vertices to screen coordinates.<BR>To read only the Position Matrix, or 
only the Projection Matrix: Use Load Identity on the OTHER matrix, so the 
ClipMatrix becomes equal to the DESIRED matrix (multiplied by the Identity 
Matrix, which has no effect on the result).<BR><BR><B>4000680h..6A3h - 
VECMTX_RESULT - Read Current Directional Vector Matrix (R)</B><BR>This 36-byte 
region (9 words) contains the m[0..8] values of the Current Directional Vector 
Matrix, arranged in 3x3 Matrix format (the fourth row/column may contain any 
values).<BR>Make sure that the Geometry Engine is stopped (GXSTAT.27) before 
reading from these registers.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixtypes></A><FONT size=+2>&nbsp;DS 3D Matrix 
      Types</FONT></TD></TR></TBODY></TABLE><BR>Essentially, all matrices in the NDS 
are 4x4 Matrices, consisting of 16 values, m[0..15]. Each element is a signed 
fixed-point 32bit number, with a fractional part in the lower 12bits.<BR>The 
other Matrix Types are used to reduce the number of parameters being 
transferred, for example, 3x3 Matrix requires only nine parameters, the other 
seven elements are automatically set to 0 or 1.0 (whereas "1.0" means "1 SHL 12" 
in 12bit fixed-point notation).<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>   _      4x4 Matrix       _        _    Identity Matrix    _</B>
  | m[0]  m[1]  m[2]  m[3]  |      |  1.0   0     0     0    |
  | m[4]  m[5]  m[6]  m[7]  |      |  0     1.0   0     0    |
  | m[8]  m[9]  m[10] m[11] |      |  0     0     1.0   0    |
  |_m[12] m[13] m[14] m[15]_|      |_ 0     0     0     1.0 _|
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>   _      4x3 Matrix       _        _  Translation Matrix   _</B>
  | m[0]  m[1]  m[2]   0    |      |  1.0   0     0     0    |
  | m[3]  m[4]  m[5]   0    |      |  0     1.0   0     0    |
  | m[6]  m[7]  m[8]   0    |      |  0     0     1.0   0    |
  |_m[9]  m[10] m[11]  1.0 _|      |_m[0]  m[1]  m[2]   1.0 _|
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>   _      3x3 Matrix       _        _     Scale Matrix      _</B>
  | m[0]  m[1]  m[2]   0    |      | m[0]   0     0     0    |
  | m[3]  m[4]  m[5]   0    |      |  0    m[1]   0     0    |
  | m[6]  m[7]  m[8]   0    |      |  0     0    m[2]   0    |
  |_ 0     0     0     1.0 _|      |_ 0     0     0     1.0 _|
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixstack></A><FONT size=+2>&nbsp;DS 3D Matrix 
      Stack</FONT></TD></TR></TBODY></TABLE><BR><B>Matrix Stack</B><BR>The NDS has 
three Matrix Stacks, and two Matrix Stack Pointers (the Coordinate Matrix stack 
pointer is also shared for Directional Matrix Stack).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Matrix Stack        Valid Stack Area    Stack Pointer
  Projection Stack    0..0  (1 entry)     0..1  (1bit) (GXSTAT: 1bit)
  Coordinate Stack    0..30 (31 entries)  0..63 (6bit) (GXSTAT: 5bit only)
  Directional Stack   0..30 (31 entries)  (uses Coordinate Stack Pointer)
  Texture Stack       One..None?          0..1  (1bit) (GXSTAT: N/A)
</PRE></TD></TR></TBODY></TABLE>The initial value of the Stack Pointers is zero, 
the current value of the pointers can be read from GXSTAT (read-only), that 
register does also indicate stack overflows (errors flag gets set on read/write 
to invalid entries, ie. entries 1 or 1Fh..3Fh). For all stacks, the upper half 
(ie. 1 or 20h..3Fh) are mirrors of the lower half (ie. 0 or 
0..1Fh).<BR><BR><B>4000444h - Cmd 11h - MTX_PUSH - Push Current Matrix on Stack 
(W)</B><BR>Parameters: None. Sets [S]=C, and then S=S+1.<BR><BR><B>4000448h - 
Cmd 12h - MTX_POP - Pop Current Matrix from Stack (W)</B><BR>Sets S=S-N, and 
then C=[S].<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter Bit0-5:  Stack Offset (signed value, -30..+31) (usually +1)
  Parameter Bit6-31: Not used
</PRE></TD></TR></TBODY></TABLE>Offset N=(+1) pops the most recently pushed 
value, larger offsets of N&gt;1 will "deallocate" N values (and load the Nth 
value into C). Zero or negative values can be used to pop previously 
"deallocated" values.<BR>The stack has only one level (at address 0) in 
projection mode, in that mode, the parameter value is ignored, the offset is 
always +1 in that mode.<BR><BR><B>400044Ch - Cmd 13h - MTX_STORE - Store Current 
Matrix on Stack (W)</B><BR>Sets [N]=C. The stack pointer S is not used, and is 
left unchanged.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter Bit0-4:  Stack Address (0..30) (31 causes overflow in GXSTAT.15)
  Parameter Bit5-31: Not used
</PRE></TD></TR></TBODY></TABLE>The stack has only one level (at address 0) in 
projection mode, in that mode, the parameter value is 
ignored.<BR><BR><B>4000450h - Cmd 14h - MTX_RESTORE - Restore Current Matrix 
from Stack (W)</B><BR>Sets C=[N]. The stack pointer S is not used, and is left 
unchanged.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter Bit0-4:  Stack Address (0..30) (31 causes overflow in GXSTAT.15)
  Parameter Bit5-31: Not used
</PRE></TD></TR></TBODY></TABLE>The stack has only one level (at address 0) in 
projection mode, in that mode, the parameter value is ignored.<BR><BR>In 
Projection mode, the parameter for POP, STORE, and RESTORE is unused - not sure 
if the parameter (ie. a dummy value) is - or is not - to be written to the 
command FIFO?<BR>There appear to be actually 32 entries in Coordinate &amp; 
Directional Stacks, entry 31 appears to exist, and appears to be read/write-able 
(although the stack overflow flag gets set when accessing it).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixexamplesprojection></A><FONT size=+2>&nbsp;DS 3D 
      Matrix Examples (Projection)</FONT></TD></TR></TBODY></TABLE><BR>The most 
important matrix is the Projection Matrix (to be initialized with MTX_MODE=0 via 
MTX_LOAD_4x4 command). It does specify the dimensions of the view 
volume.<BR><BR>With Perspective Projections more distant objects will appear 
smaller, with Orthogonal Projects the size of the objects is always same 
regardless of their distance.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Perspective Projection     Orthogonal Projection</B>
                  ___                  __________
       top ___----   |            top |          |
          |   view   |                |   view   |
  Eye ----|---------&gt;|        Eye ----|---------&gt;|
          |__volume  |                |  volume  |
     bottom   ----___|          bottom|__________|
        near        far             near        far
</PRE></TD></TR></TBODY></TABLE><BR>Correctly initializing the projection matrix 
(as shown in the examples below) can be quite difficult (mind that fixed point 
multiply/divide requires to adjust the fixed-point width before/after 
calculation). For beginners, it may be recommended to start with a simple 
Identity Matrix (MTX_IDENTITY command) used as Projection Matrix (ie. Ortho with 
t,b,l,r set to +/-1).<BR><BR><B>Orthogonal Projections (Ortho)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  | (2.0)/(r-l)       0             0            0     |
  |      0       (2.0)/(t-b)        0            0     |
  |      0            0        (2.0)/(n-f)       0     |
  | (l+r)/(l-r)  (b+t)/(b-t)   (n+f)/(n-f)      1.0    |
</PRE></TD></TR></TBODY></TABLE>n,f specify the distance from eye to near and 
far clip planes. t,b,l,r are the coordinates of near clip plane 
(top,bottom,left,right). For a symmetrical view (ie. the straight-ahead view 
line centered in the middle of viewport) t,b,l,r should be usually t=+ysiz/2, 
b=-ysiz/2, r=+xsiz/2, l=-xsiz/2; the (xsiz/ysiz) ratio should be usually equal 
to the viewport's (width/heigh) ratio. Examples for a asymmetrical view would be 
b=0 (frog's view), or t=0 (bird's view).<BR><BR><B>Left-Right Asymmetrical 
Perspective Projections (Frustum)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  | (2*n)/(r-l)       0             0            0     |
  |      0       (2*n)/(t-b)        0            0     |
  | (r+l)/(r-l)  (t+b)/(t-b)   (n+f)/(n-f)     -1.0    |
  |      0            0       (2*n*f)/(n-f)      0     |
</PRE></TD></TR></TBODY></TABLE>n,f,t,b,l,r have same meanings as above (Ortho), 
the difference is that more distant objects will appear smaller with Perspective 
Projection (unlike Orthogonal Projection where the size isn't affected by the 
distance).<BR><BR><B>Left-Right Symmetrical Perspective Projections 
(Perspective)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  | cos/(asp*sin)     0             0            0     |
  |      0         cos/sin          0            0     |
  |      0            0        (n+f)/(n-f)     -1.0    |
  |      0            0       (2*n*f)/(n-f)      0     |
</PRE></TD></TR></TBODY></TABLE>Quite the same as above (Frustum), but with 
symmetrical t,b values (which are in this case obtained from a vertical view 
range specified in degrees), and l,r are matched to the aspect ratio of the 
viewport (asp=height/width).<BR><BR><B>Moving the Camera</B><BR>After 
initializing the Projection Matrix, you may multiply it with Rotate and/or 
Translation Matrices to change camera's position and view direction.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixexamplesrotatescaletranslate></A><FONT 
      size=+2>&nbsp;DS 3D Matrix Examples 
  (Rotate/Scale/Translate)</FONT></TD></TR></TBODY></TABLE><BR><B>Identity 
Matrix</B><BR>The MTX_IDENTITY command can be used to initialize the Position 
Matrix before doing any Translation/Scaling/Rotation, for example:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Load(Identity)                           ;no rotation/scaling used
  Load(Identity), Mul(Rotate), Mul(Scale)  ;rotation/scaling (not so efficient)
  Load(Rotate), Mul(Scale)                 ;rotation/scaling (more efficient)
</PRE></TD></TR></TBODY></TABLE><BR><B>Rotation Matrices</B><BR>Rotation can be 
performed with MTX_MULT_3x3 command, simple examples are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Around X-Axis          Around Y-Axis          Around Z-Axis
  | 1.0  0     0   |     | cos   0    sin |     | cos   sin   0   |
  | 0    cos   sin |     | 0     1.0  0   |     | -sin  cos   0   |
  | 0    -sin  cos |     | -sin  0    cos |     | 0     0     1.0 |
</PRE></TD></TR></TBODY></TABLE><BR><B>Scale Matrix</B><BR>The MTX_SCALE command 
allows to adjust the size of the polygon. The x,y,z parameters should be 
normally all having the same value, x=y=z (unless if you want to change only the 
height of the object, for example). Identical results can be obtained with 
MTX_MULT commands, however, when using lighting (MTX_MODE=2), then scaling 
should be done ONLY with MTX_SCALE (which keeps the length of the light's 
directional vector intact).<BR><BR><B>Translation Matrix</B><BR>The MTX_TRANS 
command allows to move polygons to the desired position. The polygon VTX 
commands are spanning only a small range of coordinates (near zero-coordinate), 
so translation is required to move the polygons to other locations in the world 
coordinates. Aside from that, translation is useful for moved objects (at 
variable coordinates), and for re-using an object at various locations (eg. you 
can create a forest by translating a tree to different 
coordinates).<BR><BR><B>Matrix Multiply Order</B><BR>The Matrix must be set up 
BEFORE sending the Vertices (which are then automatically multiplied by the 
matrix). When using multiple matrices multiplied with each other: Mind that, for 
matrix maths A*B is NOT the same as B*A. For example, if you combine Rotate and 
Translate Matrices, the object will be either rotated around it's own 
zero-coordinate, or around world-space zero-coordinate, depending on the 
multiply order.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dmatrixexamplesmathsbasics></A><FONT size=+2>&nbsp;DS 3D 
      Matrix Examples (Maths Basics)</FONT></TD></TR></TBODY></TABLE><BR>Below is a 
crash-course on matrix maths. Most of it is carried out automatically by the 
hardware. So this chapter is relevant only if you are interested in details 
about what happens inside of the 3D engine.<BR><BR><B>Matrix-by-Matrix 
Multiplication</B><BR>Matrix multiplication, C = A * B, is possible only if the 
number of columns in A is equal to the number of rows in B, so it works fine 
with the 4x4 matrices which are used in the NDS. For the multiplication, assume 
matrix C to consist of elements cyx, and respecitively, matrix A and B to 
consist of elements ayx and byx. So that C = A * B looks like:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  | c11 c12 c13 c14 |     | a11 a12 a13 a14 |     | b11 b12 b13 b14 |
  | c21 c22 c23 c24 |  =  | a21 a22 a23 a24 |  *  | b21 b22 b23 b24 |
  | c31 c32 c33 c34 |     | a31 a32 a33 a34 |     | b31 b32 b33 b34 |
  | c41 c42 c43 c44 |     | a41 a42 a43 a44 |     | b41 b42 b43 b44 |
</PRE></TD></TR></TBODY></TABLE>Each element in C is calculated by multiplying 
the elements from one row in A by the elements from the corresponding column in 
B, and then taking the sum of the products, ie.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cyx = ay1*b1x + ay2*b2x + ay3*b3x + ay4*b4x
</PRE></TD></TR></TBODY></TABLE>In total, that requires 64 multiplications (four 
multiplications for each of the 16 cyx elements), and 48 additions (three per 
cyx element), the hardware carries out that operation at a relative decent speed 
of 30..35 clock cycles, possibly by performing several multiplications 
simultaneously with separate multiply units.<BR>Observe that for matrix 
multiplication, A*B is NOT the same as B*A.<BR><BR><B>Matrix-by-Vector &amp; 
Vector-by-Matrix Multiplication</B><BR>Vectors are Matrices with only one row, 
or only one column. Multiplication works as for normal matrices; the number of 
rows/columns must match up, repectively, row-vectors can be multiplied by a 
matrices; and matrices can be multiplied by column-vectors (but not vice-versa). 
Eg. C = A * B:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                                                  | b11 b12 b13 b14 |
  | c11 c12 c13 c14 |  =  | a11 a12 a13 a14 |  *  | b21 b22 b23 b24 |
                                                  | b31 b32 b33 b34 |
                                                  | b41 b42 b43 b44 |
</PRE></TD></TR></TBODY></TABLE>The formula for calculating the separate 
elements is same as above,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cyx = ay1*b1x + ay2*b2x + ay3*b3x + ay4*b4x
</PRE></TD></TR></TBODY></TABLE>Of which, C and A have only one y-index, so one 
may replace "cyx and ayx" by "c1x and a1x", or completely leave out the y-index, 
ie. "cx and ax".<BR><BR><B>Matrix-by-Number Multiplication</B><BR>Simply 
multiply all elements of the Matrix by the number, C = A * n:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cyx = ayx*n
</PRE></TD></TR></TBODY></TABLE>Of course, works also with vectors (matrices 
with only one row/column).<BR><BR><B>Matrix-to-Matrix 
Addition/Subtraction</B><BR>Both matrices must have the same number of rows 
&amp; columns, add/subtract all elements with corresponding elements in other 
matrix, C = A +/- B:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cyx = ayx +/- byx
</PRE></TD></TR></TBODY></TABLE>Of course, works also with vectors (two matrices 
with only one row/column).<BR><BR><B>Vectors</B><BR>A vector, for example 
(x,y,z), consists of offsets along x-,y-, and z-axis. The line from origin to 
origin-plus-offset is having two characteristics: A direction, and a 
length.<BR>The length (aka magnitude) can be calculated as 
L=sqrt(x^2+y^2+z^2).<BR><BR><B>Vector-by-Vector Multiplication</B><BR>This can 
be processed as LineVector*RowVector, so the result is a number (aka scalar) 
(aka a matrix with only 1x1 elements). Multiplying two (normalized) vectors 
results in: "cos(angle)=vec1*vec2", ie. the consine of the angle between the two 
vectors (eg. used for light vectors). Multiplying a vector with itself, and 
taking the square root of the result obtains its length, ie. 
"length=sqrt(vec^2)".<BR>That stuff should be done with 3-dimensional vectors 
(not 4-dimensionals).<BR><BR><B>Normalized Vectors</B><BR>Normalized Vectors 
(aka Unit Vectors) are vectors with length=1.0. To normalize a vector, divide 
its coordinates by its length, ie. x=x/L, y=y/L, z=z/L, the direction remains 
the same, but the length is now 1.0.<BR>On the NDS, normalized vectors should 
have a length of something less than 1.0 (eg. something like 0.99) because 
several NDS registers are limited to 1bit sign, 0bit interger, Nbit fraction 
part (so vectors that are parallel with the x,y,z axes, or that become parallel 
to them after rotation, cannot have a length of 1.0).<BR><BR><B>Fixed-Point 
Numbers</B><BR>The NDS uses fixed-point numbers (rather than floating point 
numbers). Addition and Subtraction works as with normal integers, provided that 
the fractional part is the same for both numbers. If it is not the same: 
Shift-left the value with the smaller fractional part.<BR>For multiplication, 
the fractional part of result is the sum of the fractional parts (eg. 12bit 
fraction * 12bit fraction = 24bit fraction; shift-right the result by 12 to 
convert it 12bit fraction). The NDS matrix multiply unit is maintaining the full 
24bit fraction when processing the<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  cyx = ay1*b1x + ay2*b2x + ay3*b3x + ay4*b4x
</PRE></TD></TR></TBODY></TABLE>formula, ie. the three additions are using full 
24bit fractions (with carry-outs to upper bits), the final result of the 
additions is then shifted-right by 12.<BR>For division, it's vice versa, the 
fractions of the operands are substracted, 24bit fraction / 12bit fraction = 
12bit fraction. When dividing two 12bit numbers, shift-left the first number by 
12 before division to get a result with 12bit fractional 
part.<BR><BR><B>Four-Dimensional Matrices</B><BR>The NDS uses four-dimensional 
matrices and vectors, ie. matrices with 4x4 elements, and vectors with 4 
elements. The first three elements are associated with the X,Y,Z-axes of the 
three-dimensional space. The fourth element is somewhat a "W-axis".<BR>With 
4-dimensional matrices, the Translate matrix can be used to move an object to 
another position. Ie. once when you've setup a matrix (which may consists of 
pre-multiplied scaling, rotation, translation matrices), then that matrix can be 
used on vertices to perform the rotation, scaling, translation all-at-once; by a 
single Vector*Matrix operation.<BR>With 3-dimensional matrices, translation 
would require a separate addition, additionally to the multiply 
operation.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dpolygonattributes></A><FONT size=+2>&nbsp;DS 3D Polygon 
      Attributes</FONT></TD></TR></TBODY></TABLE><BR><B>40004A4h - Cmd 29h - 
POLYGON_ATTR - Set Polygon Attributes (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Light 0..3 Enable Flags (each bit: 0=Disable, 1=Enable)
  4-5   Polygon Mode  (0=Modulation,1=Decal,2=Toon/Highlight Shading,3=Shadow)
  6     Polygon Back Surface   (0=Hide, 1=Render)  ;Line-segments are always
  7     Polygon Front Surface  (0=Hide, 1=Render)  ;rendered (no front/back)
  8-10  Not used
  11    Depth-value for Translucent Polygons  (0=Keep Old, 1=Set New Depth)
  12    Far-plane intersecting polygons       (0=Hide, 1=Render/clipped)
  13    1-Dot polygons behind DISP_1DOT_DEPTH (0=Hide, 1=Render)
  14    Depth Test, Draw Pixels with Depth    (0=Less, 1=Equal) (usually 0)
  15    Fog Enable                            (0=Disable, 1=Enable)
  16-20 Alpha      (0=Wire-Frame, 1..30=Translucent, 31=Solid)
  21-23 Not used
  24-29 Polygon ID (00h..3Fh, used for translucent, shadow, and edge-marking)
  30-31 Not used
</PRE></TD></TR></TBODY></TABLE>Writes to POLYGON_ATTR have no effect until next 
BEGIN_VTXS command.<BR>Changes to the Light bits have no effect until lighting 
is re-calculated by Normal command. The interior of Wire-frame polygons is 
transparent (Alpha=0), and only the lines at the polygon edges are rendered, 
using a fixed Alpha value of 31.<BR><BR><B>4000480h - Cmd 20h - COLOR - Directly 
Set Vertex Color (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-4    Red
  Parameter 1, Bit 5-9    Green
  Parameter 1, Bit 10-14  Blue
  Parameter 1, Bit 15-31  Not used
</PRE></TD></TR></TBODY></TABLE>The 5bit RGB values are internally expanded to 
6bit RGB as follows: X=X*2+(X+31)/32, ie. zero remains zero, all other values 
are X=X*2+1.<BR>Aside from by using the Color command, the color can be also 
changed by MaterialColor0 command (if MaterialColor0.Bit15 is set, it acts 
identical as the Color Command), and by the Normal command (which calculates the 
color based on light/material parameters).<BR><BR><B>Depth Test (aka DepthFunc 
in OpenGL)</B><BR>The Depth Test compares the depth of the pixels of the polygon 
with the depth of previously rendered polygons (or of the rear plane if there 
have been none rendered yet). The new pixels are drawn if the new depth is Less 
(closer to the camera), or if it is Equal, as selected by POLYGON_ATTR.Bit14. 
The latter comparision mode draws pixels only on exact matches, so the results 
may be unpredictable due to rounding errors; one situation that does work stable 
is if both polygons use the same vertices, eg. it can be used to put a grafitti 
texture (consisting of solid and transparent pixels) onto a wall.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dpolygondefinitionsbyvertices></A><FONT size=+2>&nbsp;DS 3D 
      Polygon Definitions by Vertices</FONT></TD></TR></TBODY></TABLE><BR>The DS 
supports polygons with 3 or 4 edges, triangles and quadliterals.<BR>The position 
of the edges is defined by vertices, each consisting of (x,y,z) 
values.<BR><BR>For Line Segments, use Triangles with twice the same vertex, Line 
Segments are rendered always because they do not have any front and back 
sides.<BR>The Prohibited Quad shapes may produce unintended results, namely, 
that are Quads with crossed sides, and quads with angles greater than 180 
degrees.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Separate Tri.     Triangle Strips   Line Segment
  v0                 v2___v4____v6
  |\      v3         /|\  |\    /\     v0    v1
  | \     /\      v0( | \ | \  /  \     ------
  |__\   /__\        \|__\|__\/____\         v2
  v1 v2 v4  v5       v1   v3  v5   v7
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Separate Quads          Quadliteral Strips         Prohibited Quads
    v0__v3                 v0__v2____v4     v10__    v0__v3     v4
     /  \   v4____v7        /  \     |\ _____ / /v11   \/       |\
    /    \   |    \        /    \    | |v6 v8| /       /\     v5| \
   /______\  |_____\      /______\___|_|_____|/       /__\     /___\
   v1    v2  v5    v6     v1    v3  v5 v7   v9       v2   v1   v6   v7
</PRE></TD></TR></TBODY></TABLE><BR>The vertices are normally arranged 
anti-clockwise, except that: in triangle-strips each second polygon uses 
clockwise arranged vertices, and quad-stripes are sorts of "up-down" arranged 
(whereas "up" and "down" may be anywhere due to rotation). Other arrangements 
may result in quads with crossed lines, or may swap the front and back sides of 
the polygon (above examples are showing the front sides).<BR><BR><B>4000500h - 
Cmd 40h - BEGIN_VTXS - Start of Vertex List (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-1    Primitive Type (0..3, see below)
  Parameter 1, Bit 2-31   Not used
</PRE></TD></TR></TBODY></TABLE>Indicates the Start of a Vertex List, and its 
Primitive Type:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  Separate Triangle(s)    ;3*N vertices per N triangles
  1  Separate Quadliteral(s) ;4*N vertices per N quads
  2  Triangle Strips         ;3+(N-1) vertices per N triangles
  3  Quadliteral Strips      ;4+(N-1)*2 vertices per N quads
</PRE></TD></TR></TBODY></TABLE>The BEGIN_VTX command should be followed by 
VTX_-commands to define the Vertices of the list, and should be then terminated 
by END_VTX command.<BR>BEGIN_VTX additionally applies changes to 
POLYGON_ATTR.<BR><BR><B>4000504h - Cmd 41h - END_VTXS - End of Vertex List 
(W)</B><BR>Parameters: None. This is a Dummy command for OpenGL compatibility. 
It should be used to terminate a BEGIN_VTX, VTX_&lt;values&gt; sequence. 
END_VTXS is possibly required for Nintendo's software emulator? On real NDS 
consoles (and in no$gba) it does have no effect, it can be left out, or can be 
issued multiple times inside of a vertex list, without disturbing the 
display.<BR><BR><B>400048Ch - Cmd 23h - VTX_16 - Set Vertex XYZ Coordinates 
(W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
  Parameter 1, Bit 16-31  Y-Coordinate (signed, with 12bit fractional part)
  Parameter 2, Bit 0-15   Z-Coordinate (signed, with 12bit fractional part)
  Parameter 2, Bit 16-31  Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000490h - Cmd 24h - VTX_10 - Set Vertex 
XYZ Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-9    X-Coordinate (signed, with 6bit fractional part)
  Parameter 1, Bit 10-19  Y-Coordinate (signed, with 6bit fractional part)
  Parameter 1, Bit 20-29  Z-Coordinate (signed, with 6bit fractional part)
  Parameter 1, Bit 30-31  Not used
</PRE></TD></TR></TBODY></TABLE>Same as VTX_16, with only one parameter, with 
smaller fractional part.<BR><BR><B>4000494h - Cmd 25h - VTX_XY - Set Vertex XY 
Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
  Parameter 1, Bit 16-31  Y-Coordinate (signed, with 12bit fractional part)
</PRE></TD></TR></TBODY></TABLE>The Z-Coordinate is kept unchanged, and re-uses 
the value from previous VTX.<BR><BR><B>4000498h - Cmd 26h - VTX_XZ - Set Vertex 
XZ Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
  Parameter 1, Bit 16-31  Z-Coordinate (signed, with 12bit fractional part)
</PRE></TD></TR></TBODY></TABLE>The Y-Coordinate is kept unchanged, and re-uses 
the value from previous VTX.<BR><BR><B>400049Ch - Cmd 27h - VTX_YZ - Set Vertex 
YZ Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   Y-Coordinate (signed, with 12bit fractional part)
  Parameter 1, Bit 16-31  Z-Coordinate (signed, with 12bit fractional part)
</PRE></TD></TR></TBODY></TABLE>The X-Coordinate is kept unchanged, and re-uses 
the value from previous VTX.<BR><BR><B>40004A0h - Cmd 28h - VTX_DIFF - Set 
Relative Vertex Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-9    X-Difference (signed, with 9bit fractional part)
  Parameter 1, Bit 10-19  Y-Difference (signed, with 9bit fractional part)
  Parameter 1, Bit 20-29  Z-Difference (signed, with 9bit fractional part)
  Parameter 1, Bit 30-31  Not used
</PRE></TD></TR></TBODY></TABLE>Sets XYZ-Coordinate relative to the 
XYZ-Coordinates from previous VTX, that is, the Difference values are divided by 
8, and are then added to the old coordinates (due to the division, the 9bit 
fractional part goes to the LSBs of the 12bit fractional part of the 
coordinates).<BR>The result of the addition should not overflow 16bit vertex 
coordinate range (1bit sign, 3bit integer, 12bit fraction).<BR><BR><B>Notes on 
VTX commands</B><BR>On each VTX command, the viewport coordinates of the vertex 
are calculated and stored in Vertex RAM,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ( xx, yy, zz, ww ) = ( x, y, z, 1.0 ) * ClipMatrix
</PRE></TD></TR></TBODY></TABLE>The actual screen position (in pixels) is 
then,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  screen_x = (xx+ww)*viewport_width / (2*ww) + viewport_x1
  screen_y = (yy+ww)*viewport_height / (2*ww) + viewport_y1
</PRE></TD></TR></TBODY></TABLE>Each VTX command that completes the definition 
of a polygon (ie. each 3rd for Separate Trangles) does additionally store data 
in Polygon List RAM.<BR>VTX commands may be issued only between Begin and End 
commands.<BR><BR><B>Clipping</B><BR>Polygons are clipped to the 6 sides of the 
view volume (ie. to the left, right, top, bottom, near, and far edges). If one 
or more vertic(es) exceed one of these sides, then these vertic(es) are replaced 
by two newly created vertices (which are located on the intersections of the 
polygon edges and the view volume edge).<BR>Depending on the number of clipped 
vertic(es), this may increase or decrease the number of entries in Vertex RAM 
(ie. minus N clipped vertices, plus 2 new vertices). Also, clipped polygons 
which are part of polygon strips are converted to separate polygons (which does 
increase number of entries in Vertex RAM). Polygons that are fully outside of 
the View Volume aren't stored in Vertex RAM, nor in Polygon RAM (the only 
exception are polygons that are located exactly one pixel below of, or right of 
lower/right edges, which appear to be accidently stored in memory).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dpolygonlightparameters></A><FONT size=+2>&nbsp;DS 3D 
      Polygon Light Parameters</FONT></TD></TR></TBODY></TABLE><BR>The lighting 
operation is performed by executing the Normal command (which sets the 
VertexColor based on the Light/Material parameters) (to the rest of the hardware 
it doesn't matter if the VertexColor was set by Color command or by Normal 
command). Light is calculated only for the Front side of the polygon (assuming 
that the Normal is matched to that side), so the Back side will be (incorrectly) 
using the same color.<BR><BR><B>40004C8h - Cmd 32h - LIGHT_VECTOR - Set Light's 
Directional Vector (W)</B><BR>Sets direction of the specified light (ie. the 
light selected in Bit30-31).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-9   Directional Vector's X component (1bit sign + 9bit fractional part)
  10-19 Directional Vector's Y component (1bit sign + 9bit fractional part)
  20-29 Directional Vector's Z component (1bit sign + 9bit fractional part)
  30-31 Light Number                     (0..3)
</PRE></TD></TR></TBODY></TABLE>Upon executing this command, the incoming vector 
is multiplied by the current Directional Matrix, the result is then applied as 
LightVector. This allows to rotate the light direction. However, normally, to 
keep the light unrotated, be sure to use LoadIdentity (in MtxMode=2) before 
setting the LightVector.<BR><BR><B>40004CCh - Cmd 33h - LIGHT_COLOR - Set Light 
Color (W)</B><BR>Sets the color of the specified light (ie. the light selected 
in Bit30-31).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   Red          (0..1Fh)      ;\light color this will be combined with
  5-9   Green        (0..1Fh)      ; diffuse, specular, and ambient colors
  10-14 Blue         (0..1Fh)      ;/upon execution of the normal command
  15-29 Not used
  30-31 Light Number (0..3)
</PRE></TD></TR></TBODY></TABLE><BR><B>40004C0h - Cmd 30h - DIF_AMB - 
MaterialColor0 - Diffuse/Ambient Reflect. (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   Diffuse Reflection Red     ;\light(s) that directly hits the polygon,
  5-9   Diffuse Reflection Green   ; ie. max when NormalVector has opposite
  10-14 Diffuse Reflection Blue    ;/direction of LightVector
  15    Set Vertex Color (0=No, 1=Set Diffuse Reflection Color as Vertex Color)
  16-20 Ambient Reflection Red     ;\light(s) that indirectly hits the polygon,
  21-25 Ambient Reflection Green   ; ie. assuming that light is reflected by
  26-30 Ambient Reflection Blue    ;/walls/floor, regardless of LightVector
  31    Not used
</PRE></TD></TR></TBODY></TABLE>With Bit15 set, the lower 15bits are applied as 
VertexColor (exactly as when when executing the Color command), the purpose is 
to use it as default color (eg. when outcommenting the Normal command), 
normally, when using lighting, the color setting gets overwritten (as soon as 
executing the Normal command).<BR><BR><B>40004C4h - Cmd 31h - SPE_EMI - 
MaterialColor1 - Specular Ref. &amp; Emission (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4   Specular Reflection Red    ;\light(s) reflected towards the camera,
  5-9   Specular Reflection Green  ; ie. max when NormalVector is in middle of
  10-14 Specular Reflection Blue   ;/LightVector and ViewDirection
  15    Specular Reflection Shininess Table (0=Disable, 1=Enable)
  16-20 Emission Red               ;\light emitted by the polygon itself,
  21-25 Emission Green             ; ie. regardless of light colors/vectors,
  26-30 Emission Blue              ;/and no matter if any lights are enabled
  31    Not used
</PRE></TD></TR></TBODY></TABLE>Caution: Specular Reflection WON'T WORK when the 
ProjectionMatrix is rotated.<BR><BR><B>40004D0h - Cmd 34h - SHININESS - Specular 
Reflection Shininess Table (W)</B><BR>Write 32 parameter words (each 32bit word 
containing four 8bit entries), entries 0..3 in the first word, through entries 
124..127 in the last word:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Shininess 0 (unsigned fixed-point, 0bit integer, 8bit fractional part)
  8-15  Shininess 1 ("")
  16-23 Shininess 2 ("")
  24-31 Shininess 3 ("")
</PRE></TD></TR></TBODY></TABLE>If the table is disabled (by 
MaterialColor1.Bit15), then reflection will act as if the table would be filled 
with linear increasing numbers.<BR><BR><B>4000484h - Cmd 21h - NORMAL - Set 
Normal Vector (W)</B><BR>In short, this command does calculate the VertexColor, 
based on the various light-parameters.<BR>In detail, upon executing this 
command, the incoming vector is multiplied by the current Directional Matrix, 
the result is then applied as NormalVector (giving it the same rotation as used 
for the following polygon vertices).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-9   X-Component of Normal Vector (1bit sign + 9bit fractional part)
  10-19 Y-Component of Normal Vector (1bit sign + 9bit fractional part)
  20-29 Z-Component of Normal Vector (1bit sign + 9bit fractional part)
  30-31 Not used
</PRE></TD></TR></TBODY></TABLE>Defines the Polygon's Normal. And, does then 
update the Vertex Color; by recursing the View Direction, the NormalVector, the 
LightVector(s), and Light/Material Colors. The execution time of the Normal 
command varies depending on the number of enabled light(s).<BR><BR><B>Additional 
Light Registers</B><BR>Additionally to above registers, light(s) must be enabled 
in PolygonAttr (mind that changes to PolygonAttr aren't applied until next Begin 
command). And, the Directional Matrix must be set up correctly (in MtxMode=2) 
for the LightVector and NormalVector commands, the NormalVector command 
additionally relies on the Projection Matrix (MtxMode=0).<BR><BR><B>Normal 
Vector</B><BR>The Normal vector must point "away from the polygon surface" (eg. 
for the floor, the Normal should point upwards). That direction is implied by 
the polygon vertices, however, the hardware cannot automatically calculate it, 
so it must be set manually with the Normal command (prior to the 
VTX-commands).<BR>When using lighting, the Normal command must be re-executed 
after switching Lighting on/off, or after changing light/material parameters. 
And, of course, also before defining polygons with different orientation. 
Polygons with same orientation (eg. horizontal polygon surfaces) and same 
material color can use the same Normal. Changing the Normal per polygon gives 
differently colored polygons with flat surfaces, changing the Normal per vertex 
gives the illusion of curved surfaces.<BR><BR><B>Light Vector</B><BR>Each light 
consists of parallel beams; similar to sunlight, which appears to us (due to the 
great distance) to consist of parallel beams, all emmitted into the same 
direction; towards Earth.<BR>In reality, light is emitted into ALL directions, 
originated from the light source (eg. a candle), the hardware doesn't support 
that type of non-parallel light. However, the light vectors can be changed per 
polygon, so a polygon that is located north of the light source may use 
different light direction than a polygon that is east of the light 
source.<BR>And, of course, Light 0..3 may (and should) have different 
directions.<BR><BR><B>Normalized Vectors</B><BR>The Normal Vector and the Light 
Vectors should be normalized (ie. their length should be 1.0) (in practice: 
something like 0.99, since the registers have only fractional parts) (a length 
of 1.0 can cause overflows).<BR><BR><B>Lighting Limitations</B><BR>The 
functionality of the light feature is limited to reflecting light to the camera 
(light is not reflected to other polygons, nor does it cast shadows on other 
polygons). However, independently of the lighting feature, the DS hardware does 
allow to create shadows, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dshadowpolygons">DS 3D Shadow 
Polygons</A><BR><BR><B>Internal Operation on Normal Command</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  IF TexCoordTransformMode=2 THEN TexCoord=NormalVector*Matrix (see TexCoord)
  NormalVector=NormalVector*DirectionalMatrix
  VertexColor = EmissionColor
  FOR i=0 to 3
   IF PolygonAttrLight[i]=enabled THEN
    DiffuseLevel = max(0,-(LightVector[i]*NormalVector))
    ShininessLevel = max(0,(-HalfVector[i])*(NormalVector))^2
    IF TableEnabled THEN ShininessLevel = ShininessTable[ShininessLevel]
    ;note: below processed separately for the R,G,B color components...
    VertexColor = VertexColor + SpecularColor*LightColor[i]*ShininessLevel
    VertexColor = VertexColor + DiffuseColor*LightColor[i]*DiffuseLevel
    VertexColor = VertexColor + AmbientColor*LightColor[i]
   ENDIF
  NEXT i
</PRE></TD></TR></TBODY></TABLE><BR><B>Internal Operation on Light_Vector 
Command (for Light i)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LightVector[i] = (LightVector*DirectionalMatrix)
  HalfVector[i] = (LightVector[i]+LineOfSightVector)/2
</PRE></TD></TR></TBODY></TABLE><BR><B>LineOfSightVector (how it SHOULD 
work)</B><BR>Ideally, the LineOfSightVector should point from the camera to the 
vertic(es), however, the vertic(es) are still unknown at time of normal command, 
so it is just pointing from the camera to the screen, ie.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LineOfSightVector = (0,0,-1.0)
</PRE></TD></TR></TBODY></TABLE>Moreover, the LineOfSightVector should be 
multiplied by the Projection Matrix (so the vector would get rotated accordingly 
when the camera gets rotated), and, after multiplication by a scaled matrix, 
it'd be required to normalize the resulting vector.<BR><BR><B>LineOfSightVector 
(how it DOES actually work)</B><BR>However, the NDS cannot normalize vectors by 
hardware, and therefore, it does completely leave out the 
LineOfSightVector*ProjectionMatrix multiplication. So, the LineOfSightVector is 
always (0,0,-1.0), no matter of any camera rotation. That means,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Specular Reflection WON'T WORK when the ProjectionMatrix is rotated (!)
</PRE></TD></TR></TBODY></TABLE>So, if you want to rotate the "camera" (in 
MTX_MODE=0), then you must instead rotate the "world" in the opposite direction 
(in MTX_MODE=2).<BR>That problem applies only to Specular Reflection, ie. only 
if Lighting is used, and only if the Specular Material Color is 
nonzero.<BR><BR><B>Maths Notes</B><BR>Note on Vector*Vector multiplication: 
Processed as LineVector*RowVector, so the result is a number (aka scalar) (aka a 
matrix with only 1x1 elements), multiplying two (normalized) vectors results in: 
"cos(angle)=vec1*vec2", ie. the consine of the angle between the two 
vectors.<BR>The various Normal/Light/Half/Sight vectors are only 3-dimensional 
(x,y,z), ie. only the upper-left 3x3 matrix elements are used on multiplications 
with the 4x4 DirectionalMatrix.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dshadowpolygons></A><FONT size=+2>&nbsp;DS 3D Shadow 
      Polygons</FONT></TD></TR></TBODY></TABLE><BR>The DS hardware's Light-function 
allows to reflect light to the camera, it does not reflect light to other 
polygons, and it does not cast any shadows. For shadows at fixed locations it'd 
be best to pre-calculate their shape and position, and to change the vertex 
color of the shaded polygons.<BR>Additionally, the Shadow Polygon feature can be 
used for to create animated shadows, ie. moved objects and variable light 
sources.<BR><BR><B>Shadow Polygons and Shadow Volume</B><BR>The software must 
define a Shadow Volume (ie. the region which doesn't contain light), the 
hardware does then automatically draw the shadow on all pixels whose 
x/y/z-coordinates are inside of that region.<BR>The Shadow Volume must be 
defined by several Shadow Polygons which are enclosing the shaded region. The 
'top' of the shadow volume should be usually translated to the position of the 
object that casts the shadow, if the light direction changes then the shadow 
volume should be also rotated to match the light direction. The 'length' of the 
shadow volume should be (at least) long enough to reach from the object to the 
walls/floor where the shadow is to be drawn. The shadow volume must be passed 
TWICE to the hardware:<BR><BR><B>Step 1 - Shadow Volume for Mask</B><BR>Set 
Polygon_Attr Mode=Shadow, PolygonID=00h, Back=Render, Front=Hide, 
Alpha=01h..1Eh, and pass the shadow volume (ie. the shadow polygons) to the 
geometry engine.<BR>The Back=Render / Front=Hide setting causes the 'rear-side' 
of the shadow volume to be rendered, of course only as far as it is in front of 
other polygons. The Mode=Shadow / ID=00h setting causes the polygon NOT to be 
drawn to the Color Buffer - instead, flags are set in the Stencil Buffer (to be 
used in Step 2).<BR><BR><B>Step 2 - Shadow Volume for Rendering</B><BR>Simply 
repeat step 1, but with Polygon_Attr Mode=Shadow, PolygonID=01h..3Fh, 
Back=Render(what/why?), Front=Render, Alpha=01h..1Eh.<BR>The Front=Render 
setting causes the 'front-side' of the shadow volume to be rendered, again, only 
as far as it is in front of other polygons. The Mode=Shadow / ID&gt;00h setting 
causes the polygon to be drawn to the Color Buffer as usually, but only if the 
Stencil Buffer bits are zero (ie. the portion from Step 1 is excluded) 
(additionally, Step 2 resets the stencil bits after checking them). Moreover, 
the shadow is rendered only if its Polygon ID differs from the ID in the 
Attribute Buffer.<BR><BR><B>Shadow Alpha and Shadow Color</B><BR>The 
Alpha=Translucent setting in Step 1 and 2 ensures that the Shadow is drawn AFTER 
the normal (opaque) polygons have been rendered. In Step 2 it does additionally 
specify the 'intensity' of the shadow. For normal shadows, the Vertex Color 
should be usually black, however, the shadow volume may be also used as 
'spotlight volume' when using other colors.<BR><BR><B>Rendering Order</B><BR>The 
Mask Volume must be rendered prior to the Rendering Volume, ie. Step 1 and 2 
must be performed in that order, and, to keep that order intact, Auto-sorting 
must be disabled in the following Swap_Buffers command.<BR>The shadow volume 
must be rendered after the 'target' polygons have been rendered, for opaque 
targets this is done automatically (due to the translucent alpha setting; 
translucent polygons are always rendered last, even with auto-sort 
disabled).<BR><BR><B>Translucent Targets</B><BR>Casting shadows on Translucent 
Polygons. First draw the translucent target (with update depth buffer enabled, 
required for the shadow z-coordinates), then draw the Shadow Mask/Rendering 
volumes.<BR>Due to the updated depth buffer the shadow will be cast only on the 
translucent target (not on any other polygons underneath of the translucent 
polygon). If you want the shadow to appear on both: Draw draw the Shadow 
Mask/Rendering volume TWICE (once before, and once after to drawing the 
translucent target).<BR><BR><B>Polygon ID and Fog Enable</B><BR>The "Render only 
if Polygon ID differs" feature (see Step 2) allows to prevent the shadow to be 
cast on the object that casts the shadow (ie. the object and shadow should have 
the same IDs). The feature also allows to select whether overlapping shadows 
(with same/different IDs) are shaded once or twice.<BR>The old Fog Enable flag 
in the Attribute Buffer is ANDed with the Fog Enable flag of the Shadow 
Polygons, this allows to exclude Fog in shaded regions.<BR><BR><B>Shadow Volume 
Open/Closed Shapes</B><BR>Normally, the shadow volume should have a closed 
shape, ie. should have a rear-sides (step 1), and corresponding front-sides 
(step 2) for all possible viewing angles. That is required for the shadow to be 
drawn correctly, and also for the Stencil Buffer to be reset to zero (in step 2, 
so that the stencil bits won't disturb other shadow volumes).<BR>Due to that, 
drawing errors may occur if the shadow volume's front or rear side gets clipped 
by near/far clip plane.<BR>One exception is that the volume doesn't need a 
bottom-side (with a suitable volume length, the bottom may be left open, since 
it vanishes in the floor/walls anyways).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtextureattributes></A><FONT size=+2>&nbsp;DS 3D Texture 
      Attributes</FONT></TD></TR></TBODY></TABLE><BR><B>4000488h - Cmd 22h - TEXCOORD 
- Set Texture Coordinates (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   S-Coordinate (X-Coordinate in Texture Source)
  Parameter 1, Bit 16-31  T-Coordinate (Y-Coordinate in Texture Source)
  Both values are 1bit sign + 11bit integer + 4bit fractional part.
  A value of 1.0 (=1 SHL 4) equals to one Texel.
</PRE></TD></TR></TBODY></TABLE>With Position 0.0 , 0.0 drawing starts from 
upperleft of the Texture.<BR>With positive offsets, drawing origin starts more 
"within" the texture.<BR>With negative offsets, drawing starts "before" the 
texture, the preceeding region is left blank/transparent ? (unless texture 
repeat is enabled).<BR>"When texture mapping, the Geometry Engine works faster 
if you issue commands in the order TexCoord -&gt; Normal -&gt; 
Vertex."<BR><BR><B>40004A8h - Cmd 2Ah - TEXIMAGE_PARAM - Set Texture Parameters 
(W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Texture VRAM Offset div 8 (0..FFFFh -&gt; 512K RAM in Slot 0,1,2,3)
        (VRAM must be allocated as Texture data, see Memory Control chapter)
  16    Repeat in S Direction (0=Freeze last texel-column, 1=Repeat Texture)
  17    Repeat in T Direction (0=Freeze last texel-row,    1=Repeat Texture)
  18    Flip in S Direction   (0=No, 1=Flip each 2nd Texture) (requires Repeat)
  19    Flip in T Direction   (0=No, 1=Flip each 2nd Texture) (requires Repeat)
  20-22 Texture S-Size        (for N=0..7: Size=(8 SHL N); ie. 8..1024 texels)
  23-25 Texture T-Size        (for N=0..7: Size=(8 SHL N); ie. 8..1024 texels)
  26-28 Texture Format        (0..7, see below)
  29    Color 0 of 4/16/256-Color Palettes (0=Displayed, 1=Made Transparent)
  30-31 Texture Coordinates Transformation Mode (0..3, see below)
</PRE></TD></TR></TBODY></TABLE>Texture Formats:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  No Texture
  1  A3I5 Translucent Texture
  2  4-Color Palette Texture
  3  16-Color Palette Texture
  4  256-Color Palette Texture
  5  4x4-Texel Compressed Texture
  6  A5I3 Translucent Texture
  7  Direct Texture
</PRE></TD></TR></TBODY></TABLE>Texture Coordinates Transformation Modes:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  Do not Transform texture coordinates
  1  TexCoord source
  2  Normal source
  3  Vertex source
</PRE></TD></TR></TBODY></TABLE>The S-Direction equals to the horizontal 
direction of the source bitmap.<BR>For a texture shape "&gt;" S-repeat and 
S-flip look like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  No Repeat   Repeat    Repeat+Flip
  &gt;-------    &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  &gt;&lt;&gt;&lt;&gt;&lt;&gt;&lt;
</PRE></TD></TR></TBODY></TABLE>The T-Direction, T-repeat, and T-flip are the 
same in vertical direction.<BR><BR><B>40004ACh - Cmd 2Bh - PLTT_BASE - Set 
Texture Palette Base Address (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12   Palette Base Address (div8 or div10h, see below)
         (Not used for Texture Format 7: Direct Color Texture)
         (0..FFF8h/8 for Texture Format 2: ie. 4-color-palette Texture)
         (0..17FF0h/10h for all other Texture formats)
  13-31  Not used
</PRE></TD></TR></TBODY></TABLE>The palette data occupies 16bit per color, 
Bit0-4: Red, Bit5-9: Green, Bit10-14: Blue, Bit15: Not used.<BR>(VRAM must be 
allocated as Texture Palette, there can be up to 6 Slots allocated, ie. the 
addressable 18000h bytes, see Memory Control chapter)<BR><BR><B>TexImageParam 
and TexPlttBase</B><BR>Can be issued per polygon (except within polygon 
strips).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtextureformats></A><FONT size=+2>&nbsp;DS 3D Texture 
      Formats</FONT></TD></TR></TBODY></TABLE><BR><B>Format 2: 4-Color Palette 
Texture</B><BR>Each Texel occupies 2bit, the first Texel is located in LSBs of 
1st byte.<BR>In this format, the Palette Base is specified in 8-byte steps; all 
other formats use 16-byte steps (see PLTT_BASE register).<BR><BR><B>Format 3: 
16-Color Palette Texture</B><BR>Each Texel occupies 4bit, the 1st Texel is 
located in LSBs of 1st byte.<BR><BR><B>Format 4: 256-Color Palette 
Texture</B><BR>Each Texel occupies 8bit, the 1st Texel is located in 1st 
byte.<BR><BR><B>Format 7: Direct Color Texture</B><BR>Each Texel occupies 16bit, 
the 1st Texel is located in 1st halfword.<BR>Bit0-4: Red, Bit5-9: Green, 
Bit10-14: Blue, Bit15: Alpha<BR><BR><B>Format 1: A3I5 Translucent Texture (3bit 
Alpha, 5bit Color Index)</B><BR>Each Texel occupies 8bit, the 1st Texel is 
located in 1st byte.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-4: Color Index (0..31) of a 32-color Palette
  Bit5-7: Alpha       (0..7; 0=Transparent, 7=Solid)
</PRE></TD></TR></TBODY></TABLE>The 3bit Alpha value (0..7) is internally 
expanded into a 5bit Alpha value (0..31) as follows: 
Alpha=(Alpha*4)+(Alpha/2).<BR><BR><B>Format 6: A5I3 Translucent Texture (5bit 
Alpha, 3bit Color Index)</B><BR>Each Texel occupies 8bit, the 1st Texel is 
located in 1st byte.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-2: Color Index (0..7) of a 8-color Palette
  Bit3-7: Alpha       (0..31; 0=Transparent, 31=Solid)
</PRE></TD></TR></TBODY></TABLE><BR><B>Format 5: 4x4-Texel Compressed 
Texture</B><BR>Consists of 4x4 Texel blocks in Slot 0 or 2, 32bit per block, 
2bit per Texel,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-7   Upper 4-Texel row (LSB=first/left-most Texel)
  Bit8-15  Next  4-Texel row ("")
  Bit16-23 Next  4-Texel row ("")
  Bit24-31 Lower 4-Texel row ("")
</PRE></TD></TR></TBODY></TABLE>Additional Palette Index Data for each 4x4 Texel 
Block is located in Slot 1,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-13  Palette Offset in 4-byte steps; Addr=(PLTT_BASE*10h)+(Offset*4)
  Bit14-15 Transparent/Interpolation Mode (0..3, see below)
</PRE></TD></TR></TBODY></TABLE>whereas, the Slot 1 offset is related to above 
Slot 0 or 2 offset,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  slot1_addr = slot0_addr / 2           ;lower 64K of Slot1 assoc to Slot0
  slot1_addr = slot2_addr / 2 + 10000h  ;upper 64K of Slot1 assoc to Slot2
</PRE></TD></TR></TBODY></TABLE>The 2bit Texel values (0..3) are intepreted 
depending on the Mode (0..3),<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Texel  Mode 0       Mode 1             Mode 2         Mode 3
  0      Color 0      Color0             Color 0        Color 0
  1      Color 1      Color1             Color 1        Color 1
  2      Color 2      (Color0+Color1)/2  Color 2        (Color0*5+Color1*3)/8
  3      Transparent  Transparent        Color 3        (Color0*3+Color1*5)/8
</PRE></TD></TR></TBODY></TABLE>Mode 1 and 3 are using only 2 Palette Colors 
(which requires only half as much Palette memory), the 3rd (and 4th) Texel 
Colors are automatically set to above values (eg. to gray-shades if color 0 and 
1 are black and white).<BR>Note: The maximum size for 4x4-Texel Compressed 
Textures is 1024x512 or 512x1024 (which are both occupying the whole 128K in 
slot 0 or 2, plus 64K in slot1), a larger size of 1024x1024 cannot be used 
because of the gap between slot 0 and 2.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtexturecoordinates></A><FONT size=+2>&nbsp;DS 3D Texture 
      Coordinates</FONT></TD></TR></TBODY></TABLE><BR>For textured polygons, a texture 
coordinate must be associated with each vertex of the polygon. The coordinates 
(S,T) are defined by TEXCOORD command (typically issued prior to each VTX 
command), and can be optionally automatically transformed, by the Transformation 
Mode selected in TEXIMAGE_PARAM register.<BR><BR><B>Texture 
Matrix</B><BR>Although the texture matrix is 4x4, with values m[0..15], only the 
left two columns of this matrix are actually used. In Mode 2 and 3, the bottom 
row of the matrix is replaced by S and T values from most recent TEXCOORD 
command.<BR><BR><B>Texture Coordinates Transformation Mode 0 - No 
Transform</B><BR>The values are set upon executing the TEXCOORD command,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ( S' T' )  =  ( S  T )
</PRE></TD></TR></TBODY></TABLE>Simple coordinate association, without using the 
Texture Matrix at all.<BR><BR><B>Texture Coordinates Transformation Mode 1 - 
TexCoord source</B><BR>The values are calculated upon executing the TEXCOORD 
command,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                                     | m[0]  m[1]  |
  ( S' T' )  =  ( S  T 1/16 1/16 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_m[12] m[13]_|
</PRE></TD></TR></TBODY></TABLE>Can be used to produce a simple texture 
scrolling, rotation, or scaling, by setting a translate, rotate, or scale matrix 
for the texture matrix.<BR><BR><B>Texture Coordinates Transformation Mode 2 - 
Normal source</B><BR>The values are calculated upon executing the NORMAL 
command,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                                     | m[0]  m[1]  |
  ( S' T' )  =  ( Nx  Ny  Nz 1.0 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_S     T    _|
</PRE></TD></TR></TBODY></TABLE>Can be used to produce spherical reflection 
mapping by setting in the texture matrix to the current directional vector 
matrix, multiplied by a scaling matrix that expands the directional vector space 
from -1.0..+1.0 to one half of the texture size. For that purpose, translate the 
origin of the texture coordinate to the center of the spherical texture by using 
TexCoord command.<BR><BR><B>Texture Coordinates Transformation Mode 3 - Vertex 
source</B><BR>The values are calculated upon executing any VTX commands,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                                     | m[0]  m[1]  |
  ( S' T' )  =  ( Vx  Vy  Vz 1.0 ) * | m[4]  m[5]  |
                                     | m[8]  m[9]  |
                                     |_S     T    _|
</PRE></TD></TR></TBODY></TABLE>Can be used to produce texture scrolls dependent 
on the View coordinates by copying the current position coordinate matrix into 
the texture matrix.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtextureblending></A><FONT size=+2>&nbsp;DS 3D Texture 
      Blending</FONT></TD></TR></TBODY></TABLE><BR>Polygon pixels consist of a Vertex 
Color, and of Texture Colors.<BR>These colors can be blended as described below. 
Or, to use only either one:<BR>To use only the Vertex Color: Select No Texture 
in TEXIMAGE_PARAM.<BR>To use only the Texture Color: Select Modulation Mode and 
Alpha=31 in POLYGON_ATTR, and set COLOR to 7FFFh (white), or to gray values (to 
decrease brightness of the texture color).<BR><BR><B>Vertex Color 
(Rv,Gv,Bv,Av)</B><BR>The Vertex Color (Rv,Gv,Bv) can be changed per Vertex 
(either by Color, Normal, or Material0 command), pixels between vertices are 
shaded to medium values of the surrounding vertices. The Vertex Alpha (Av), can 
be changed only per polygon (by PolygonAttr command).<BR><BR><B>Texture Colors 
(Rt,Gt,Bt,At)</B><BR>The Texture Colors (Rt,Gt,Bt), and Alpha value (At), are 
defined by the Texture Bitmap. For formats without Alpha value, assume At=31 
(solid), and for formats with 1bit Alpha assume At=A*31.<BR><BR><B>Shading Table 
Colors (Rs,Gs,Bs)</B><BR>In Toon/Hightlight Shading Mode, the red component of 
the Vertex Color (Rv) is mis-used as an index in the Shading Table; to read 
Shading Colors (Rs,Gs,Bs) from the table; the green and blue components of the 
Vertex Color (Gv,Bv) are unused in this mode. The Vertex Alpha (Av) is kept 
used.<BR>Shading is used in Polygon Mode 2, whether it is Toon or Hightlight 
Shading is selected in DISP3DCNT; this is a per-frame selection, so only either 
one can be used.<BR><BR><B>Texture Blending - Modulation Mode (Polygon Attr Mode 
0)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R = ((Rt+1)*(Rv+1)-1)/64
  G = ((Gt+1)*(Gv+1)-1)/64
  B = ((Bt+1)*(Bv+1)-1)/64
  A = ((At+1)*(Av+1)-1)/64
</PRE></TD></TR></TBODY></TABLE>The multiplication result is decreased intensity 
(unless both factors are 63).<BR><BR><B>Texture Blending - Decal Mode (Polygon 
Attr Mode 1)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R = (Rt*At + Rv*(63-At))/64  ;except, when At=0: R=Rv, when At=31: R=Rt
  G = (Gt*At + Gv*(63-At))/64  ;except, when At=0: G=Gv, when At=31: G=Gt
  B = (Bt*At + Bv*(63-At))/64  ;except, when At=0: B=Bv, when At=31: B=Bt
  A = Av
</PRE></TD></TR></TBODY></TABLE>The At value is used (only) as ratio for Texture 
color vs Vertex Color.<BR><BR><B>Texture Blending - Toon Shading (Polygon Mode 
2, DISP3DCNT=Toon)</B><BR>The vertex color Red component (Rv) is used as an 
index in the toon table.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R = ((Rt+1)*(Rs+1)-1)/64   ;Rs=ToonTableRed[Rv]
  G = ((Gt+1)*(Gs+1)-1)/64   ;Gs=ToonTableGreen[Rv]
  B = ((Bt+1)*(Bs+1)-1)/64   ;Bs=ToonTableBlue[Rv]
  A = ((At+1)*(Av+1)-1)/64
</PRE></TD></TR></TBODY></TABLE>This is same as Modulation Mode, but using 
Rs,Gs,Bs instead Rv,Gv,Bv.<BR><BR><B>Texture Blending - Highlight Shading 
(Polygon Mode 2, DISP3DCNT=Highlight)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  R = ((Rt+1)*(Rs+1)-1)/64+Rs ;truncated to MAX=63
  G = ((Gt+1)*(Gs+1)-1)/64+Gs ;truncated to MAX=63
  B = ((Bt+1)*(Bs+1)-1)/64+Bs ;truncated to MAX=63
  A = ((At+1)*(Av+1)-1)/64
</PRE></TD></TR></TBODY></TABLE>Same as Toon Shading, with additional addition 
offset, the addition may increase the intensity, however, it may also change the 
hue of the color.<BR><BR>Above formulas are for 6bit RGBA values, ie. 5bit 
values internally expanded to 6bit as such: IF X&gt;0 THEN 
X=X*2+1.<BR><BR><B>Uni-Colored Textures</B><BR>Although textures are normally 
containing "pictures", in some cases it makes sense to use "blank" textures that 
are filled with a single color:<BR>Wire-frame polygons are always having Av=31, 
however, they can be made transparent by using Translucent Textures (ie. A5I3 or 
A3I5 formats) with At&lt;31.<BR>In Toon/Hightlight shading modes, the Vertex 
Color is mis-used as table index, however, Toon/Hightlight shading can be used 
on uni-colored textures, which is more or less the same as using Toon/Hightlight 
shading on uni-colored Vertex-colors.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtoonedgefog></A><FONT size=+2>&nbsp;DS 3D Toon, Edge, 
      Fog</FONT></TD></TR></TBODY></TABLE><BR><B>4000380h..3BFh - TOON_TABLE - Toon 
Table (W)</B><BR>This 64-byte region contains the 32 toon colors (16bit per 
color), used for both Toon and Highlight Shading. In both modes, the Red (R) 
component of the RGBA vertex color is mis-used as index to obtain the new RGB 
value from the toon table, vertex Alpha (A) is kept used as is.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-4: Red, Bit5-9: Green, Bit10-14: Blue, Bit15: Not Used
</PRE></TD></TR></TBODY></TABLE>Shading can be enabled (per polygon) in 
Polygon_Attr, whether it is Toon or Highlight Shading is set (per frame) in 
DISP3DCNT. For more info on shading, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#ds3dtextureblending">DS 3D Texture 
Blending</A><BR><BR><B>4000330h..33Fh - EDGE_COLOR - Edge Colors 0..7 
(W)</B><BR>This 16-byte region contains the 8 edge colors (16bit per color), 
Edge Color 0 is used for Polygon ID 00h..07h, Color 1 for ID 08h..0Fh, and so 
on.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-4: Red, Bit5-9: Green, Bit10-14: Blue, Bit15: Not Used
</PRE></TD></TR></TBODY></TABLE>Edge Marking allows to mark the edges of an 
object (whose polygons all have the same ID) in a wire-frame style. Edge Marking 
can be enabled (per frame) in DISP3DCNT. When enabled, the polygon edges are 
drawn at the edge color, but only if the old ID value in the Attribute Buffer is 
different than the Polygon ID of the new polygon, so no edges are drawn between 
connected or overlapping polygons with same ID values. Edge Marking works only 
on opaque polygons?<BR><BR><B>4000358h - FOG_COLOR - Fog Color (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4    Fog Color, Red
  5-9    Fog Color, Green
  10-14  Fog Color, Blue
  15     Not used
  16-20  Fog Alpha
  21-31  Not used
</PRE></TD></TR></TBODY></TABLE>Fog can be used to let more distant polygons to 
disappear in foggy grayness (or in darkness, or other color). This is 
particulary useful to "hide" the far clip plane. Fog can be enabled in 
DISP3DCNT.Bit6, moreover, when enabled, it can be activated or deactivated per 
polygon (POLYGON_ATTR.Bit15), and per Rear-plane (see there).<BR><BR><B>400035Ch 
- FOG_OFFSET - Fog Offset (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-14   Fog Offset (Unsigned) (0..7FFFh=Depth) (and FOG_SHIFT in DISP3DCNT)
  15-31  Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000360h..37Fh - FOG_TABLE - Fog Density 
Table (W)</B><BR>This 32-byte region contains the 32 Fog Densities (one byte per 
entry),<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-6    Fog Density (00h..7Fh = None..Full) (usually increasing values)
  7      Not used
</PRE></TD></TR></TBODY></TABLE>For n=0..1Fh, FOG_OFFSET=Port 400035Ch, 
FOG_SHIFT=DISP3DCNT.Bit8..11:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Density[n] --&gt; used at Depth = FOG_OFFSET+(400h SHR FOG_SHIFT)*(n+1)
</PRE></TD></TR></TBODY></TABLE>Density[0,31] values are used for all pixels 
that are closer or more distant than the Density[0,31] depth boundaries. Density 
is linear interpolated for pixels that are between two Density depth 
boundaries.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dstatus></A><FONT size=+2>&nbsp;DS 3D 
  Status</FONT></TD></TR></TBODY></TABLE><BR><B>4000600h - GXSTAT - Geometry 
Engine Status Register (R and R/W)</B><BR>Bit 30-31 are R/W. Writing "1" to 
Bit15 does reset the Error Flag (Bit15), and additionally resets the Projection 
Stack Pointer (Bit13), and probably (?) also the Texture Stack Pointer. All 
other GXSTAT bits are read-only.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     BoxTest,PositionTest,VectorTest Busy (0=Ready, 1=Busy)
  1     BoxTest Result  (0=All Outside View, 1=Parts or Fully Inside View)
  2-7   Not used
  8-12  Position &amp; Vector Matrix Stack Level (0..31) (lower 5bit of 6bit value)
  13    Projection Matrix Stack Level        (0..1)
  14    Matrix Stack Busy (0=No, 1=Yes; Currently executing a Push/Pop command)
  15    Matrix Stack Overflow/Underflow Error (0=No, 1=Error/Acknowledge/Reset)
  16-24 Number of 40bit-entries in Command FIFO  (0..256)
 (24)   Command FIFO Full (MSB of above)  (0=No, 1=Yes; Full)
  25    Command FIFO Less Than Half Full  (0=No, 1=Yes; Less than Half-full)
  26    Command FIFO Empty                (0=No, 1=Yes; Empty)
  27    Geometry Engine Busy (0=No, 1=Yes; Busy; Commands are executing)
  28-29 Not used
  30-31 Command FIFO IRQ (0=Never, 1=Less than half full, 2=Empty, 3=Reserved)
</PRE></TD></TR></TBODY></TABLE>When GXFIFO IRQ is enabled (setting 1 or 2), the 
IRQ flag (IF.Bit21) is set while and as long as the IRQ condition is true (and 
attempts to acknowledge the IRQ by writing to IF.Bit21 have no effect). So that, 
the IRQ handler must either fill the FIFO, or disable the IRQ (setting 0), 
BEFORE trying to acknowledge the IRQ.<BR><BR><B>4000604h - RAM_COUNT - Polygon 
List &amp; Vertex RAM Count Register (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11   Number of Polygons currently stored in Polygon List RAM (0..2048)
  12-15  Not used
  16-28  Number of Vertices currently stored in Vertex RAM       (0..6144)
  13-15  Not used
</PRE></TD></TR></TBODY></TABLE>If a SwapBuffer command has been sent, then the 
counters are reset 10 cycles (at 33.51MHz clock) after next 
VBlank.<BR><BR><B>4000320h - RDLINES_COUNT - Rendered Line Count Register 
(R)</B><BR>Rendering starts in scanline 214, the rendered lines are stored in a 
buffer that can hold up to 48 scanlines. The actual screen output begins after 
scanline 262, the lines are then read from the buffer and sent to the display. 
Simultaneously, the rendering engine keeps writing new lines to the buffer 
(ideally at the same speed than display output, so the buffer would always 
contain 48 pre-calculated lines).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-5    Minimum Number (minus 2) of buffered lines in previous frame (0..46)
  6-31   Not used
</PRE></TD></TR></TBODY></TABLE>If rendering becomes slower than the display 
output, then the number of buffered lines decreases. Smaller values in RDLINES 
indicate that additional load to the rendering engine may cause buffer 
underflows in further frames, if so, the program should reduce the number of 
polygons to avoid display glitches.<BR>Even if RDLINES becomes zero, it doesn't 
indicate whether actual buffer underflows have occured or not (underflows are 
indicated in DISP3DCNT Bit12).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dtests></A><FONT size=+2>&nbsp;DS 3D 
  Tests</FONT></TD></TR></TBODY></TABLE><BR><B>40005C0h - Cmd 70h - BOX_TEST - 
Test if Cuboid Sits inside View Volume (W)</B><BR>The BoxTest result indicates 
if one or more of the 6 faces of the box are fully or parts of inside of the 
view volume. Can be used to reduce unneccessary overload, ie. if the result is 
false, then the program can skip drawing of objects which are inside of the 
box.<BR>BoxTest verifies only if the faces of the box are inside view volume, 
and so, it will return false if the whole view volume is located inside of the 
box (still objects inside of the box may be inside of view).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   X-Coordinate
  Parameter 1, Bit 16-31  Y-Coordinate
  Parameter 2, Bit 0-15   Z-Coordinate
  Parameter 2, Bit 16-31  Width  (presumably: X-Offset?)
  Parameter 3, Bit 0-15   Height (presumably: Y-Offset?)
  Parameter 3, Bit 16-31  Depth  (presumably: Z-Offset?)
  All values are 1bit sign, 3bit integer, 12bit fractional part
</PRE></TD></TR></TBODY></TABLE>The result of the "coordinate+offset" additions 
should not overflow 16bit vertex coordinate range (1bit sign, 3bit integer, 
12bit fraction).<BR>Before using BoxTest, be sure that far-plane-intersecting 
&amp; 1-dot polygons are enabled, if they aren't: Send the PolygonAttr command 
(with bit12,13 set to enable them), followed by dummy Begin and End commands 
(required to apply the new PolygonAttr settings). BoxTest should not be issued 
within Begin/End.<BR>After sending the BoxTest command, wait until GXSTAT.Bit0 
indicates Ready, then read the result from GXSTAT.Bit1.<BR><BR><B>40005C4h - Cmd 
71h - POS_TEST - Set Position Coordinates for Test (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-15   X-Coordinate
  Parameter 1, Bit 16-31  Y-Coordinate
  Parameter 2, Bit 0-15   Z-Coordinate
  Parameter 2, Bit 16-31  Not used
  All values are 1bit sign, 3bit integer, 12bit fractional part.
</PRE></TD></TR></TBODY></TABLE>Multiplies the specified line-vector (x,y,z,1) 
by the clip coordinate matrix.<BR>After sending the command, wait until 
GXSTAT.Bit0 indicates Ready, then read the result from POS_RESULT registers. 
POS_TEST can be issued anywhere, except within polygon 
strips.<BR><BR><B>4000620h..62Fh - POS_RESULT - Position Test Results 
(R)</B><BR>This 16-byte region (4 words) contains the resulting clip coordinates 
(x,y,z,w) from the POS_TEST command. Each value is 1bit sign, 19bit integer, 
12bit fractional part.<BR><BR><B>40005C8h - Cmd 72h - VEC_TEST - Set Directional 
Vector for Test (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Parameter 1, Bit 0-9    X-Component
  Parameter 1, Bit 10-19  Y-Component
  Parameter 1, Bit 20-29  Z-Component
  Parameter 1, Bit 30-31  Not used
  All values are 1bit sign, 9bit fractional part.
</PRE></TD></TR></TBODY></TABLE>Multiplies the specified line-vector (x,y,z,0) 
by the directional vector matrix. Similar as for the NORMAL command, it does 
require Matrix Mode 2 (ie. Position &amp; Vector Simultaneous Set 
mode).<BR>After sending the command, wait until GXSTAT.Bit0 indicates Ready, 
then read the result ("the directional vector in the View coordinate space") 
from VEC_RESULT registers.<BR><BR><B>4000630h..635h - VEC_RESULT - Vector Test 
Results (R)</B><BR>This 6-byte region (3 halfwords) contains the resulting 
vector (x,y,z) from the VEC_TEST command. Each value is 4bit sign, 0bit integer, 
12bit fractional part. The 4bit sign is either 0000b (positive) or 1111b 
(negative).<BR>There is no integer part, so values &gt;=1.0 or &lt;-1.0 will 
cause overflows.<BR>(Eg. +1.0 aka 1000h will be returned as -1.0 aka F000h due 
to overflow and sign-expansion).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3drearplane></A><FONT size=+2>&nbsp;DS 3D 
    Rear-Plane</FONT></TD></TR></TBODY></TABLE><BR>Other docs seem to refer to this 
as Clear-plane, rather than Rear-plane, anyways, the plane can be an image, so 
it isn't always "cleared".<BR>The view order is as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  --&gt; 2D Layers --&gt; 3D Polygons --&gt; 3D Rear-plane --&gt; 2D Layers --&gt; 2D Backdrop
</PRE></TD></TR></TBODY></TABLE>The rear-plane can be disabled (by making it 
transparent; alpha=0), so that the 2D layers become visible as background.<BR>2D 
layers can be moved in front of, or behind the 3D layer-group (which is 
represented as BG0 to the 2D Engine), 2D layers behind BG0 can be used instead 
of, or additionally to the rear-plane.<BR><BR>The rear-plane can be initialized 
via below two registers (so all pixels in the plane have the same colors and 
attributes), this method is used when DISP3DCNT.14 is zero:<BR><BR><B>4000350h - 
CLEAR_COLOR - Clear Color Attribute Register (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-4    Clear Color, Red
  5-9    Clear Color, Green
  10-14  Clear Color, Blue
  15     Fog (enables Fog to the rear-plane) (doesn't affect Fog of polygons)
  16-20  Alpha
  21-23  Not used
  24-29  Clear Polygon ID (affects edge-marking, at the screen-edges?)
  30-31  Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000354h - CLEAR_DEPTH - Clear Depth 
Register (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-14   Clear Depth (0..7FFFh) (usually 7FFFh = most distant)
  15     Not used
  16-31  See Port 4000356h, CLRIMAGE_OFFSET
</PRE></TD></TR></TBODY></TABLE>The 15bit Depth is expanded to 24bit as 
"X=(X*200h)+((X+1)/8000h)*1FFh".<BR><BR><B>Rear Color/Depth 
Bitmaps</B><BR>Alternately, the rear-plane can be initialized by bitmap data 
(allowing to assign different colors &amp; attributes to each pixel), this 
method is used when DISP3DCNT.14 is set:<BR>Consists of two bitmaps (one with 
color data, one with depth data), each containing 256x256 16bit entries, and so, 
each occupying a whole 128K slot,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Rear Color Bitmap (presumably taken from Texture Slot 2, or 3?)
    0-4    Clear Color, Red
    5-9    Clear Color, Green
    10-14  Clear Color, Blue
    15     Alpha (0=Transparent, 1=Solid) (equivalent to 5bit-alpha 0 and 31)
  Rear Depth Bitmap (presumably taken from Texture Slot 3, or 2?)
    0-14   Clear Depth, expanded to 24bit as X=(X*200h)+((X+1)/8000h)*1FFh
    15     Clear Fog (Initial fog enable value)
</PRE></TD></TR></TBODY></TABLE>This method requires VRAM to be allocated to 
Texture Slot 2 and 3 (see Memory Control chapter). Of course, in that case the 
VRAM is used as Rear-plane, and cannot be used for Textures.<BR>The bitmap 
method is restricted to 1bit alpha values (the register-method allows to use a 
5bit alpha value).<BR>The Clear Polygon ID is kept defined in the CLEAR_COLOR 
register, even in bitmap mode.<BR><BR><B>4000356h - CLRIMAGE_OFFSET - Rear-plane 
Bitmap Scroll Offsets (W)</B><BR>The visible portion of the bitmap is 256x192 
pixels (regardless of the viewport setting, which is used only for polygon 
clipping). Internally, the bitmap is 256x256 pixels, so the bottom-most 64 rows 
are usually offscreen, unless scrolling is used to move them into view.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-7   X-Offset (0..255; 0=upper row of bitmap)
  Bit8-14  Y-Offset (0..255; 0=left column of bitmap)
</PRE></TD></TR></TBODY></TABLE>The bitmap wraps to the upper/left edges when 
exceeding the lower/right edges.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=ds3dfinal2doutput></A><FONT size=+2>&nbsp;DS 3D Final 2D 
      Output</FONT></TD></TR></TBODY></TABLE><BR>The final 3D image (consisting of 
polygons and rear-plane) is passed to 2D Engine A as BG0 layer (provided that 
DISPCNT is configured to use 3D as BG0).<BR><BR><B>Scrolling</B><BR>The BG0HOFS 
register (4000010h) can be used the scroll the 3D layer horizontally, the scroll 
region is 512 pixels, consisting of 256 pixels for the 3D image, followed by 256 
transparent pixels, and then wrapped to the 3D image again. Vertical scrolling 
(and rotation/scaling) cannot be used on the 3D layer.<BR><BR><B>BG Priority 
Order</B><BR>The lower 2bit of the BG0CNT register (4000008h) control the 
priority relative to other BGs and OBJs, so the 3D layer can be in front of or 
behing 2D layers. All other bits in BG0CNT have no effect on 3D, namely, mosaic 
cannot be used on the 3D layer.<BR><BR><B>Special Effects</B><BR>Special Effects 
Registers (4000050h..54h) can be used as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Brightness up/down with BG0 as 1st Target via EVY   (as for 2D)
  Blending with BG0 as 2nd Target via EVA/EVB         (as for 2D)
  Blending with BG0 as 1st Target via 3D Alpha-values (unlike as for 2D)
</PRE></TD></TR></TBODY></TABLE>The latter method probably (?) uses per-pixel 3D 
alpha values as such: EVA=A/2, and EVB=16-A/2, without using the EVA/EVB 
settings in 4000052h.<BR><BR><B>Window Feature</B><BR>Window Feature 
(4000040h..4Bh) can be used as for 2D.<BR>"If the 3D screen has highest 
priority, then alpha-blending is always enabled, regardless of the Window 
Control register's color effect enable flag [ie. regardless of Bit5 of WIN0IN, 
WIN1IN, WINOBJ, WINOUT registers]"... not sure if that is true, and if it 
superseedes the effect selection in Port 4000050h...?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssound></A><FONT size=+2>&nbsp;DS 
Sound</FONT></TD></TR></TBODY></TABLE><BR>The DS contains 16 hardware sound 
channels.<BR>The console contains two speakers, arranged left and right of the 
upper screen, and so, provides stereo sound even without using the headphone 
socket.<BR><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dssoundchannels015">DS Sound Channels 
0..15</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dssoundcontrolregisters">DS Sound 
Control Registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dssoundcapture">DS Sound 
Capture</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dssoundblockdiagrams">DS Sound Block 
Diagrams</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dssoundnotes">DS 
Sound Notes</A><BR><BR>Power control<BR>When restoring power supply to the sound 
circuit, do not output any sound during the first 15 milliseconds.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssoundchannels015></A><FONT size=+2>&nbsp;DS Sound Channels 
      0..15</FONT></TD></TR></TBODY></TABLE><BR>Each of the 16 sound channels occopies 
16 bytes in the I/O region, starting with channel 0 at 4000400h..400040Fh, up to 
channel 15 at 40004F0h..40004FFh.<BR><BR><B>40004x0h - NDS7 - SOUNDxCNT - Sound 
Channel X Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-6    Volume Mul   (0..127=silent..loud)
  Bit7      Not used     (always zero)
  Bit8-9    Volume Div   (0=Normal, 1=Div2, 2=Div4, 3=Div16)
  Bit10-14  Not used     (always zero)
  Bit15     Hold         (0=Normal, 1=Hold last sample after one-shot sound)
  Bit16-22  Panning      (0..127=left..right) (64=half volume on both speakers)
  Bit23     Not used     (always zero)
  Bit24-26  Wave Duty    (0..7) ;HIGH=(N+1)*12.5%, LOW=(7-N)*12.5% (PSG only)
  Bit27-28  Repeat Mode  (0=Manual, 1=Loop Infinite, 2=One-Shot, 3=Prohibited)
  Bit29-30  Format       (0=PCM8, 1=PCM16, 2=IMA-ADPCM, 3=PSG/Noise)
  Bit31     Start/Status (0=Stop, 1=Start/Busy)
</PRE></TD></TR></TBODY></TABLE>All channels support ADPCM/PCM formats, PSG 
rectangular wave can be used only on channels 8..13, and white noise only on 
channels 14..15.<BR><BR><B>40004x4h - NDS7 - SOUNDxSAD - Sound Channel X Data 
Source Register (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-26  Source Address (must be word aligned, bit0-1 are always zero)
  Bit27-31 Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>40004x8h - NDS7 - SOUNDxTMR - Sound 
Channel X Timer Register (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-15  Timer Value, Sample frequency, timerval=-(33513982/2)/freq
</PRE></TD></TR></TBODY></TABLE>The PSG Duty Cycles are composed of eight 
"samples", and so, the frequency for Rectangular Wave is 1/8th of the selected 
sample frequency.<BR>For PSG Noise, the noise frequency is equal to the sample 
frequency.<BR><BR><B>40004xAh - NDS7 - SOUNDxPNT - Sound Channel X Loopstart 
Register (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-15  Loop Start, Sample loop start position
           (counted in words, ie. N*4 bytes)
</PRE></TD></TR></TBODY></TABLE><BR><B>40004xCh - NDS7 - SOUNDxLEN - Sound 
Channel X Length Register (W)</B><BR>The number of samples for N words is 4*N 
PCM8 samples, 2*N PCM16 samples, or 8*(N-1) ADPCM samples (the first word 
containing the ADPCM header). The Sound Length is not used in PSG mode.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-21  Sound length (counted in words, ie. N*4 bytes)
  Bit22-31 Not used
</PRE></TD></TR></TBODY></TABLE>Minimum length (the sum of PNT+LEN) is 4 words 
(16 bytes), smaller values (0..3 words) are causing hang-ups (busy bit remains 
set infinite, but no sound output occurs).<BR><BR>In One-shot mode, the sound 
length is the sum of (PNT+LEN).<BR>In Looped mode, the length is 
(1*PNT+Infinite*LEN), ie. the first part (PNT) is played once, the second part 
(LEN) is repeated infinitely.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssoundcontrolregisters></A><FONT size=+2>&nbsp;DS Sound 
      Control Registers</FONT></TD></TR></TBODY></TABLE><BR><B>4000500h - NDS7 - 
SOUNDCNT - Sound Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-6   Master Volume       (0..127=silent..loud)
  Bit7     Not used            (always zero)
  Bit8-9   Left Output from    (0=Left Mixer, 1=Ch1, 2=Ch3, 3=Ch1+Ch3)
  Bit10-11 Right Output from   (0=Right Mixer, 1=Ch1, 2=Ch3, 3=Ch1+Ch3)
  Bit12    Output Ch1 to Mixer (0=Yes, 1=No) (both Left/Right)
  Bit13    Output Ch3 to Mixer (0=Yes, 1=No) (both Left/Right)
  Bit14    Not used            (always zero)
  Bit15    Master Enable       (0=Disable, 1=Enable)
  Bit16-31 Not used            (always zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>4000504h - NDS7 - SOUNDBIAS - Sound Bias 
Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-9   Sound Bias    (0..3FFh, usually 200h)
  Bit10-31 Not used      (always zero)
</PRE></TD></TR></TBODY></TABLE>After applying the master volume, the signed 
left/right audio signals are in range -200h..+1FFh (with medium level zero), the 
Bias value is then added to convert the signed numbers into unsigned values 
(with medium level 200h).<BR>BIAS output is always enabled, even when Master 
Enable (SOUNDCNT.15) is off.<BR><BR>The sampling frequency of the mixer is 
1.04876 MHz with an amplitude resolution of 24 bits, but the sampling frequency 
after mixing with PWM modulation is 32.768 kHz with an amplitude resolution of 
10 bits.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssoundcapture></A><FONT size=+2>&nbsp;DS Sound 
    Capture</FONT></TD></TR></TBODY></TABLE><BR>The DS contains 2 built-in sound 
capture devices that can capture output waveform data to memory.<BR>Sound 
capture 0 can capture output from left-mixer or output from channel 0.<BR>Sound 
capture 1 can capture output from right-mixer or output from channel 
2.<BR><BR><B>4000508h - NDS7 - SNDCAP0CNT - Sound Capture 0 Control Register 
(R/W)</B><BR><B>4000509h - NDS7 - SNDCAP1CNT - Sound Capture 1 Control Register 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0     Control of Associated Sound Channels (ANDed with Bit7)
            SNDCAP0CNT: Output Sound Channel 1 (0=As such, 1=Add to Channel 0)
            SNDCAP1CNT: Output Sound Channel 3 (0=As such, 1=Add to Channel 2)
            Caution: Addition mode works only if BOTH Bit0 and Bit7 are set.
  Bit1     Capture Source Selection
            SNDCAP0CNT: Capture 0 Source (0=Left Mixer, 1=Channel 0/Bugged)
            SNDCAP1CNT: Capture 1 Source (0=Right Mixer, 1=Channel 2/Bugged)
  Bit2     Capture Repeat        (0=Loop, 1=One-shot)
  Bit3     Capture Format        (0=PCM16, 1=PCM8)
  Bit4-6   Not used              (always zero)
  Bit7     Capture Start/Status  (0=Stop, 1=Start/Busy)
</PRE></TD></TR></TBODY></TABLE><BR><B>4000510h - NDS7 - SNDCAP0DAD - Sound 
Capture 0 Destination Address (R/W)</B><BR><B>4000518h - NDS7 - SNDCAP1DAD - 
Sound Capture 1 Destination Address (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-26  Destination address (word aligned, bit0-1 are always zero)
  Bit27-31 Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>Capture start address (also used as re-start 
address for looped capture).<BR><BR><B>4000514h - NDS7 - SNDCAP0LEN - Sound 
Capture 0 Length (W)</B><BR><B>400051Ch - NDS7 - SNDCAP1LEN - Sound Capture 1 
Length (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-15  Buffer length (1..FFFFh words) (ie. N*4 bytes)
  Bit16-31 Not used
</PRE></TD></TR></TBODY></TABLE>Minimum length is 1 word (attempts to use 0 
words are interpreted as 1 word).<BR><BR><B>SOUND1TMR - NDS7 - Sound Channel 1 
Timer shared as Capture 0 Timer</B><BR><B>SOUND3TMR - NDS7 - Sound Channel 3 
Timer shared as Capture 1 Timer</B><BR>There are no separate capture frequency 
registers, instead, the sample frequency of Channel 1/3 is shared for Capture 
0/1. These channels are intended to output the captured data, so it makes sense 
that both capture and sound output use the same frequency.<BR><BR>For Capture 0, 
a=0, b=1, x=0.<BR>For Capture 1, a=2, b=3, x=1.<BR><BR><B>Capture 
Bugs</B><BR>The NDS contains two hardware bugs which do occur when capturing 
data from ch(a) (SNDCAPxCNT.Bit1=1), if so, either bug occurs depending on 
whether ch(a)+ch(b) addition is enabled or disabled (SNDCAPxCNT.Bit0).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1) Both Negative Bug - SNDCAPxCNT Bit1=1, Bit0=0 (addition disabled)
   Capture data is accidently set to -8000h if ch(a) and ch(b) are both &lt;0.
   Otherwise the correct capture result is returned, ie. plain ch(a) data,
   not being affected by ch(b) (since addition is disabled).
   Workaround: Ensure that ch(a) and/or ch(b) are &gt;=0 (or disabled).
 2) Overflow Bug - SNDCAPxCNT Bit1=1, Bit0=1 (addition enabled)
   In this mode, Capture data isn't clipped to MinMax(-8000h,+7FFFh),
   instead, it is ANDed with FFFFh, so the sign bit is lost if the
   addition result ch(a)+ch(b) is less/greater than -8000h/+7FFFh.
   Workaround: Reduce ch(a)/ch(b) volume or data to avoid overflows.
</PRE></TD></TR></TBODY></TABLE>These bugs occur only for capture (speaker 
output remains intact), and they occur only when capturing ch(a) (capturing 
mixer-output works flawless).<BR><BR><B>ch(a)+ch(b) Channel Addition</B><BR>The 
ch(a)+ch(b) addition unit has 2 outputs, with slightly different results:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> 1) Addition Result for Capture(x) when using capture source=ch(a):
  Addition is performed always, no matter of SOUNDCNT.Bit12/13.
  And, no matter of ch(a) enable, result is plain ch(b) if ch(a) is disabled.
  Result is 16bit (plus fraction) with overflow error (see Capture Bugs).
 2) Addition Result for Mixer (towards speakers, and capture source=mixer):
  Ch(b) is muted if ch(a) is disabled.
  Ch(b) is muted if ch(b) SOUNDCNT.Bit12/13 is set to "Ch(b) not to mixer".
  Result is 17bit (plus fraction) without overflow error.
</PRE></TD></TR></TBODY></TABLE>Addition mode can be used only if the 
&lt;corresponding&gt; capture unit is enabled, ie. if SNDCAPxCNT (Bit0 AND 
Bit7)=1. If so, addition affects both mixers (and so, may also affect the 
&lt;other&gt; capture unit if it reads from mixer).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssoundblockdiagrams></A><FONT size=+2>&nbsp;DS Sound Block 
      Diagrams</FONT></TD></TR></TBODY></TABLE><BR><B>Left Mixer with Capture 
0</B><BR><B>(Right Mixer with Capture 1, respectively)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>                       _____
  Ch0.L -------------&gt;|     |  +------------------------------&gt; to Capture 0
               ___    |     |  |                  ___
  Ch1.L ---+-&gt;|Sel|--&gt;|     |  |       Ch0..Ch15 |   |
           |  |___|   |Left |--+----------------&gt;|   |
  Ch2.L ---|---------&gt;|Mixer|                    |Sel|   ______    ____
           |   ___    |     |                Ch1 |   |  |Master|  |Add |
  Ch3.L -+-|-&gt;|Sel|--&gt;|     | +-----------------&gt;|   |-&gt;|Volume|-&gt;|Bias|-&gt; L
         | |  |___|   |     | |                  |   |  |______|  |____|
  Ch4.L -|-|---------&gt;|     | |              Ch3 |   |
  ...   -|-|---------&gt;|     | | +---------------&gt;|   |
  Ch15.L-|-|---------&gt;|_____| | |   ___          |   |
         | +------------------+-|-&gt;|Add| Ch1+Ch3 |   |
         +----------------------+-&gt;|___|--------&gt;|___|
</PRE></TD></TR></TBODY></TABLE><BR><B>Channel 0 and 1, Capture 0 with input 
from Left Mixer</B><BR><B>(Channel 2 and 3, Capture 1 with input from Right 
Mixer, respectively)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ____     _________     ___     ___      ___
 |FIFO|--&gt;|Channel 0|--&gt;|Vol|--&gt;|Add|-+-&gt;|Pan|--&gt; Ch0.L
 |____|   |_________|   |___|   |___| |  |___|--&gt; Ch0.R
  ____     _________     ___      ^   |
 |FIFO|&lt;--|Capture 0|&lt;--|Sel|&lt;----|---+
 |____|   |_ _____ _|   |___|&lt;----|-------------- Left Mixer
  ____     _:Timer:_     ___     _|_      ___
 |FIFO|--&gt;|Channel 1|--&gt;|Vol|--&gt;|Sel|---&gt;|Pan|--&gt; Ch1.L
 |____|   |_________|   |___|   |___|    |___|--&gt; Ch1.R
</PRE></TD></TR></TBODY></TABLE><BR><B>Channel 4 (Channel 5..15, 
respectively)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ____     _________     ___              ___
 |FIFO|--&gt;|Channel 4|--&gt;|Vol|-----------&gt;|Pan|--&gt; Ch4.L
 |____|   |_________|   |___|            |___|--&gt; Ch4.R
</PRE></TD></TR></TBODY></TABLE><BR>The FIFO isn't used in PSG/Noise modes 
(supported on channel 8..15).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssoundnotes></A><FONT size=+2>&nbsp;DS Sound 
  Notes</FONT></TD></TR></TBODY></TABLE><BR><B>Sound delayed Start/Restart (timing 
glitch)</B><BR>A sound will be started/restarted when changing its start bit 
from 0 to 1, however, the sound won't start immediately: PSG/Noise starts after 
1 sample, PCM starts after 3 samples, and ADPCM starts after 11 samples (3 dummy 
samples as for PCM, plus 8 dummy samples for the ADPCM header).<BR><BR><B>Sound 
Stop (timing note)</B><BR>In one-shot mode, the Busy bit gets cleared 
automatically at the BEGIN of the last sample period, nethertheless (despite of 
the cleared Busy bit) the last sample is kept output until the END of the last 
sample period (or, if the Hold flag is set, then the last sample is kept output 
infinitely, that is, until Hold gets cleared, or until the sound gets 
restarted).<BR><BR><B>Hold Flag (appears useless/bugged)</B><BR>The Hold flag 
allows to keep the last sample being output infinitely after the end of one-shot 
sounds. This feature is probably intended to allow to play two continous 
one-shot sound blocks (without producing any scratch noise upon small delays 
between both blocks, which would occur if the output level would drop to 
zero).<BR>However, the feature doesn't work as intended. As described above, 
PCM8/PCM16 sound starts are delayed by 3 samples. With Hold flag set, old output 
level is acually kept intact during the 1st sample, but the output level drops 
to zero during 2nd-3rd sample, before starting the new sound in 4th 
sample.<BR><BR><B>7bit Volume and Panning Values</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  data.vol   = data*N/128
  pan.left   = data*(128-N)/128
  pan.right  = data*N/128
  master.vol = data*N/128/64
</PRE></TD></TR></TBODY></TABLE>Register settings of 0..126,127 are interpreted 
as N=0..126,128.<BR><BR><B>Max Output Levels</B><BR>When configured to max 
volume (and left-most or right-most panning), each channel can span the full 
10bit output range (-200h..1FFh) on one speaker, as well as the full 16bit input 
range (-8000h..7FFFh) on one capture unit.<BR>(It needs 2 channels to span the 
whole range on BOTH speakers/capture units.)<BR>Together, all sixteen channels 
could thus reach levels up to -1E00h..21F0h (with default BIAS=200h) on one 
speaker, and -80000h..+7FFF0h on one capture unit. However, to avoid overflows, 
speaker outputs are clipped to MinMax(0,3FFh), and capture inputs to 
MinMax(-8000h..+7FFFh).<BR><BR><B>Channel/Mixer Bit-Widths</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Step                           Bits  Min        Max
  0 Incoming PCM16 Data          16.0  -8000h     +7FFFh
  1 Volume Divider (div 1..16)   16.4  -8000h     +7FFFh
  2 Volume Factor (mul N/128)    16.11 -8000h     +7FFFh
  3 Panning (mul N/128)          16.18 -8000h     +7FFFh
  4 Rounding Down (strip 10bit)  16.8  -8000h     +7FFFh
  5 Mixer (add channel 0..15)    20.8  -80000h    +7FFF0h
  6 Master Volume (mul N/128/64) 14.21 -2000h     +1FF0h
  7 Strip fraction               14.0  -2000h     +1FF0h
  8 Add Bias (0..3FFh, def=200h) 15.0  -2000h+0   +1FF0h+3FFh
  9 Clip (min/max 0h..3FFh)      10.0  0          +3FFh
</PRE></TD></TR></TBODY></TABLE>Table shows integer.fractional bits, and min/max 
values (without fraction).<BR><BR><B>Capture Clipping/Rounding</B><BR>Incoming 
ch(a) is NOT clipped, ch(a)+ch(b) may overflow (see Capture Bugs).<BR>Incoming 
mixer data (20.8bits) is clipped to 16.8bits (MinMax -8000h..7FFFh).<BR>For PCM8 
capture format, the 16.8 bits are divided by 100h (=8.16 bits).<BR>If the MSB of 
the fractional part is set, then data is rounded towards zero.<BR>(Positive 
values are rounded down, negative values are rounded up.)<BR>The fractional part 
is then discarded, and plain integer data is captured.<BR><BR><B>PSG 
Sound</B><BR>The output volume equals to PCM16 values +7FFFh (HIGH) and -7FFFh 
(LOW).<BR>PSG sound is always Infinite (the SOUNDxLEN Register, and the 
SOUNDxCNT Repeat Mode bits have no effect). The PSG hardware doesn't support 
sound length, sweep, or volume envelopes, however, these effects can be produced 
by software with little overload (or, more typically, with enormous overload, 
depending on the programming language used).<BR><BR><B>PSG Wave Duty (channel 
8..13 in PSG mode)</B><BR>Each duty cycle consists of eight HIGH or LOW samples, 
so the sound frequency is 1/8th of the selected sample rate. The duty cycle 
always starts at the begin of the LOW period when the sound gets 
(re-)started.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  12.5% "_______-_______-_______-"
  1  25.0% "______--______--______--"
  2  37.5% "_____---_____---_____---"
  3  50.0% "____----____----____----"
  4  62.5% "___-----___-----___-----"
  5  75.0% "__------__------__------"
  6  87.5% "_-------_-------_-------"
  7   0.0% "________________________"
</PRE></TD></TR></TBODY></TABLE>The Wave Duty bits exist and are read/write-able 
on all channels (although they are actually used only in PSG mode on channels 
8-13).<BR><BR><B>PSG Noise (channel 14..15 in PSG mode)</B><BR>Noise randomly 
switches between HIGH and LOW samples, the output levels are calculated, at the 
selected sample rate, as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  X=X SHR 1, IF carry THEN Out=LOW, X=X XOR 6000h ELSE Out=HIGH
</PRE></TD></TR></TBODY></TABLE>The initial value when (re-)starting the sound 
is X=7FFFh. The formula is more or less same as "15bit polynomial counter" used 
on 8bit Gameboy and GBA.<BR><BR><B>PCM8 and PCM16</B><BR>Signed samples in range 
-80h..+7Fh (PCM8), or -8000h..+7FFFh (PCM16).<BR>The output volume of PCM8=NNh 
is equal to PCM16=NN00h.<BR><BR><B>IMA-ADPCM Format</B><BR>IMA-ADPCM is a 
Adaptive Differential Pulse Code Modulation (ADPCM) variant, designed by 
International Multimedia Association (IMA), the format is used, among others, in 
IMA-ADPCM compressed Windows .WAV files.<BR>The NDS data consist of a 32bit 
header, followed by 4bit values (so each byte contains two values, the first 
value in the lower 4bits, the second in upper 4 bits). The 32bit header contains 
initial values:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-15   Initial PCM16 Value (Pcm16bit = -7FFFh..+7FFF) (not -8000h)
  Bit16-22  Initial Table Index Value (Index = 0..88)
  Bit23-31  Not used (zero)
</PRE></TD></TR></TBODY></TABLE>In theory, the 4bit values are decoded into 
PCM16 values, as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Diff = ((Data4bit AND 7)*2+1)*AdpcmTable[Index]/8      ;see rounding-error
  IF (Data4bit AND 8)=0 THEN Pcm16bit = Max(Pcm16bit+Diff,+7FFFh)
  IF (Data4bit AND 8)=8 THEN Pcm16bit = Min(Pcm16bit-Diff,-7FFFh)
  Index = MinMax (Index+IndexTable[Data4bit AND 7],0,88)
</PRE></TD></TR></TBODY></TABLE>In practice, the first line works like so (with 
rounding-error):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Diff = AdpcmTable[Index]/8
  IF (data4bit AND 1) THEN Diff = Diff + AdpcmTable[Index]/4
  IF (data4bit AND 2) THEN Diff = Diff + AdpcmTable[Index]/2
  IF (data4bit AND 4) THEN Diff = Diff + AdpcmTable[Index]/1
</PRE></TD></TR></TBODY></TABLE>And, a note on the second/third lines (with 
clipping-error):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Max(+7FFFh) leaves -8000h unclipped (can happen if initial PCM16 was -8000h)
  Min(-7FFFh) clips -8000h to -7FFFh (possibly unlike windows .WAV files?)
</PRE></TD></TR></TBODY></TABLE>Whereas, IndexTable[0..7] = -1,-1,-1,-1,2,4,6,8. 
And AdpcmTable [0..88] =<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0007h,0008h,0009h,000Ah,000Bh,000Ch,000Dh,000Eh,0010h,0011h,0013h,0015h
  0017h,0019h,001Ch,001Fh,0022h,0025h,0029h,002Dh,0032h,0037h,003Ch,0042h
  0049h,0050h,0058h,0061h,006Bh,0076h,0082h,008Fh,009Dh,00ADh,00BEh,00D1h
  00E6h,00FDh,0117h,0133h,0151h,0173h,0198h,01C1h,01EEh,0220h,0256h,0292h
  02D4h,031Ch,036Ch,03C3h,0424h,048Eh,0502h,0583h,0610h,06ABh,0756h,0812h
  08E0h,09C3h,0ABDh,0BD0h,0CFFh,0E4Ch,0FBAh,114Ch,1307h,14EEh,1706h,1954h
  1BDCh,1EA5h,21B6h,2515h,28CAh,2CDFh,315Bh,364Bh,3BB9h,41B2h,4844h,4F7Eh
  5771h,602Fh,69CEh,7462h,7FFFh
</PRE></TD></TR></TBODY></TABLE>The closest way to reproduce the AdpcmTable with 
32bit integer maths appears:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  X=000776d2h, FOR I=0 TO 88, Table[I]=X SHR 16, X=X+(X/10), NEXT I
  Table[3]=000Ah, Table[4]=000Bh, Table[88]=7FFFh, Table[89..127]=0000h
</PRE></TD></TR></TBODY></TABLE>When using ADPCM and loops, set the loopstart 
position to the data part, rather than the header. At the loop end, the SAD 
value is reloaded to the loop start location, additionally index and pcm16 
values are reloaded to the values that have originally appeared at that 
location. Do not change the ADPCM loop start position during 
playback.<BR><BR><B>Microphone Input</B><BR>For Microphone (and Touchscreen) 
inputs, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dstouchscreencontrollertsc">DS Touch 
Screen Controller (TSC)</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dssystemandbuiltinperipherals></A><FONT size=+2>&nbsp;DS 
      System and Built-in Peripherals</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsdmatransfers">DS DMA 
Transfers</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dstimers">DS 
Timers</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsinterrupts">DS 
Interrupts</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsmaths">DS 
Maths</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsinterprocesscommunicationipc">DS 
Inter Process Communication (IPC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dskeypad">DS Keypad</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsabsentlinkport">DS Absent Link 
Port</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dsrealtimeclockrtc">DS 
Real-Time Clock (RTC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsserialperipheralinterfacebusspi">DS 
Serial Peripheral Interface Bus (SPI)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dstouchscreencontrollertsc">DS Touch 
Screen Controller (TSC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dspowermanagement">DS Power 
Management</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsdmatransfers></A><FONT size=+2>&nbsp;DS DMA 
    Transfers</FONT></TD></TR></TBODY></TABLE><BR>The DS includes four DMA channels 
for each CPU (ie. eight channels in total), which are working more or less the 
same as on GBA:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbadmatransfers">GBA DMA 
Transfers</A><BR>All NDS9 and NDS7 DMA Registers are R/W. The gamepak bit (Bit 
27) has been removed (on the NDS9 the bit is used to expand the mode setting to 
3bits).<BR><BR><B>NDS9 DMA</B><BR>Word count of all channels is expanded to 
21bits (max 1..1FFFFFh units, or 0=200000h units), and SAD/DAD registers for all 
channels support ranges of 0..0FFFFFFEh. The transfer modes (DMACNT Bit27-29) 
are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  Start Immediately
  1  Start at V-Blank
  2  Start at H-Blank (paused during V-Blank)
  3  Synchronize to start of display
  4  Main memory display
  5  DS Cartridge Slot
  6  GBA Cartridge Slot
  7  Geometry Command FIFO
</PRE></TD></TR></TBODY></TABLE><BR><B>NDS7 DMA</B><BR>Word Count, SAD, and DAD 
are R/W, aside from that they do have the same restrictions as on GBA (max 4000h 
or 10000h units, some addresses limited to 0..07FFFFFEh). DMACNT Bit27 is unused 
on NDS7. The transfer modes (DMACNT Bit28-29) are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  Start Immediately
  1  Start at V-Blank
  2  DS Cartridge Slot
  3  DMA0/DMA2: Wireless interrupt, DMA1/DMA3: GBA Cartridge Slot
</PRE></TD></TR></TBODY></TABLE><BR><B>40000E0h - NDS9 only - DMA0FILL - DMA 0 
Filldata (R/W)</B><BR><B>40000E4h - NDS9 only - DMA1FILL - DMA 1 Filldata 
(R/W)</B><BR><B>40000E8h - NDS9 only - DMA2FILL - DMA 2 Filldata 
(R/W)</B><BR><B>40000ECh - NDS9 only - DMA3FILL - DMA 3 Filldata (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-31 Filldata
</PRE></TD></TR></TBODY></TABLE>The DMA Filldata registers contain 16 bytes of 
general purpose WRAM, intended to be used as fixed source addresses for DMA 
memfill operations.<BR>This is useful because DMA cannot read from TCM, and 
reading from Main RAM would require to recurse cache &amp; write 
buffer.<BR><BR><B>NDS7 Sound DMA</B><BR>The NDS additionally includes 16 Sound 
DMA channels, plus 2 Sound Capture DMA channels (see Sound chapter). The 
priority of these channels is unknown.<BR><BR><B>NDS9 Cache, Writebuffer, DTCM, 
and ITCM</B><BR>Cache and tightly coupled memory are connected directly to the 
NDS9 CPU, without using the system bus. So that, DMA cannot access DTCM/ITCM, 
and access to cached memory regions must be handled with care: Drain the 
writebuffer before DMA-reads, and invalidate the cache after DMA-writes. 
See,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR>The CPU can be kept running during DMA, 
provided that it is accessing only TCM (or cached memory), otherwise the CPU is 
halted until DMA finishes.<BR>Respectively, interrupts executed during DMA will 
usually halt the CPU (unless the IRQ handler uses only TCM and cache; the IRQ 
vector at FFFF00xxh must be cached, or relocated to ITCM at 000000xxh, and the 
IRQ handler may not access IE, IF, or other I/O ports).<BR><BR><B>NDS Sequential 
Main Memory DMA</B><BR>Main RAM has different access time for sequential and 
non-sequential access. Normally DMA uses sequential access (except for the first 
word), however, if the source and destination addresses are both in Main RAM, 
then all accesses become non-sequential. In that case it would be faster to use 
two DMA transfers, one from Main RAM to a scratch buffer in WRAM, and one from 
WRAM to Main RAM.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dstimers></A><FONT size=+2>&nbsp;DS 
Timers</FONT></TD></TR></TBODY></TABLE><BR>Same as GBA, except F = 33.513982 MHz 
(for both NDS9 and NDS7).<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbatimers">GBA Timers</A><BR>Both NDS9 
and NDS7 have four Timers each, eight Timers in total.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsinterrupts></A><FONT size=+2>&nbsp;DS 
  Interrupts</FONT></TD></TR></TBODY></TABLE><BR><B>4000208h - NDS9/NDS7 - IME - 
16bit - Interrupt Master Enable (R/W)</B><BR>Same as GBA, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbainterruptcontrol">GBA Interrupt 
Control</A><BR><BR><B>4000210h - NDS9/NDS7 - IE - 32bit - Interrupt Enable 
(R/W)</B><BR><B>4000214h - NDS9/NDS7 - IF - 32bit - Interrupt Request Flags 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit 0-6   Same as GBA
  Bit 7     NDS7 only: SIO/RCNT/RTC (Real Time Clock)
  Bit 8..   Same as GBA
  Bit 16    IPC Sync
  Bit 17    IPC Send FIFO Empty
  Bit 18    IPC Recv FIFO Not Empty
  Bit 19    Game Card Data Transfer Completion
  Bit 20    Game Card IREQ_MC
  Bit 21    NDS9 only: Geometry Command FIFO
  Bit 22    NDS7 only: Screens unfolding
  Bit 23    NDS7 only: SPI bus
  Bit 24    NDS7 only: Wifi
  Bit 25-31 Not used
</PRE></TD></TR></TBODY></TABLE>Raw TCM-only IRQs can be processed even during 
DMA ?<BR><BR><B>DTCM+3FFCh - NDS9 - IRQ Handler (hardcoded DTCM 
address)</B><BR><B>380FFFCh - NDS7 - IRQ Handler (hardcoded RAM address)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit 0-31  Pointer to IRQ Handler
</PRE></TD></TR></TBODY></TABLE>NDS7 Handler must use ARM code, NDS9 Handler can 
be ARM/THUMB (Bit0=Thumb).<BR><BR><B>DTCM+3FF8h - NDS9 - IRQ Check Bits 
(hardcoded DTCM address)</B><BR><B>380FFF8h - NDS7 - IRQ Check Bits (hardcoded 
RAM address)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit 0-31  IRQ Flags (same format as IE/IF registers)
</PRE></TD></TR></TBODY></TABLE>When processing &amp; acknowleding interrupts 
via IF register, the user interrupt handler should also set the corresponding 
bits of the IRQ Check value (required for BIOS IntrWait and VBlankIntrWait SWI 
functions).<BR><BR>--- Below for other (non-IRQ) exceptions 
---<BR><BR><B>27FFD9Ch - RAM - NDS9 Debug Stacktop / Debug Vector 
(0=None)</B><BR><B>380FFDCh - RAM - NDS7 Debug Stacktop / Debug Vector 
(0=None)</B><BR>These addresses contain a 32bit pointer to the Debug Handler, 
and, memory below of the addresses is used as Debug Stack. The debug handler is 
called on undefined instruction exceptions, on data/prefetch aborts (caused by 
the protection unit), on FIQ (possibly caused by hardware debuggers). It is also 
called by accidental software-jumps to the reset vector, and by unused SWI 
numbers within range 0..1Fh.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmaths></A><FONT size=+2>&nbsp;DS 
Maths</FONT></TD></TR></TBODY></TABLE><BR><B>4000280h - NDS9 - DIVCNT - 16bit 
Division Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Division Mode    (0-2=See below) (3=Reserved; same as Mode 1)
  2-13  Not used
  14    Division by zero (0=Okay, 1=Division by zero error; 64bit Denom=0)
  15    Busy             (0=Ready, 1=Busy) (Execution time see below)
</PRE></TD></TR></TBODY></TABLE>Division Modes and Busy Execution Times<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Mode  Numer / Denom = Result, Remainder ; Cycles
  0     32bit / 32bit = 32bit , 32bit     ; 18 clks
  1     64bit / 32bit = 64bit , 32bit     ; 34 clks
  2     64bit / 64bit = 64bit , 64bit     ; 34 clks
</PRE></TD></TR></TBODY></TABLE>Division is started when writing to... what... 
presumably... Denom... Msb/Lsb?<BR><BR><B>4000290h - NDS9 - DIV_NUMER - 64bit 
Division Numerator (R/W)</B><BR><B>4000298h - NDS9 - DIV_DENOM - 64bit Division 
Denominator (R/W)</B><BR>Signed 64bit values (or signed 32bit values in 32bit 
modes, the upper 32bits are then unused, with one exception: the DIV0 flag in 
DIVCNT is set only if the full 64bit DIV_DENOM value is zero, even in 32bit 
mode).<BR><BR><B>40002A0h - NDS9 - DIV_RESULT - 64bit Division Quotient 
(=Numer/Denom) (R/W?)</B><BR><B>40002A8h - NDS9 - DIVREM_RESULT - 64bit 
Remainder (=Numer MOD Denom) (R/W?)</B><BR>Signed 64bit values (in 32bit modes, 
the values are sign-expanded to 64bit).<BR><BR><B>Division 
Overflows</B><BR>Overflows occur on "DIV0" and "-MAX/-1" (eg. -80000000h/-1 in 
32bit mode):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  DIV0     --&gt;  REMAIN=NUMER, RESULT=+/-1 (with sign opposite of NUMER)
  -MAX/-1  --&gt;  RESULT=-MAX               (instead +MAX)
</PRE></TD></TR></TBODY></TABLE>On overflows in 32bit/32bit=32bit mode: the 
upper 32bit of the sign-expanded 32bit result are inverted. This feature 
produces a correct 64bit (+MAX) result in case of the incorrect 32bit (-MAX) 
result. The feature also applies on DIV0 errors (which makes the sign-expanded 
64bit result even more messed-up than the normal 32bit result).<BR>The DIV0 flag 
in DIVCNT.14 indicates DENOM=0 errors (it does not indicate "-MAX errors). The 
DENOM=0 check relies on the full 64bit value (so, in 32bit mode, the flag works 
only if the unused upper 32bit of DENOM are zero).<BR><BR><B>40002B0h - NDS9 - 
SQRTCNT - 16bit - Square Root Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Mode (0=32bit input, 1=64bit input)
  1-14  Not used
  15    Busy (0=Ready, 1=Busy) (Execution time is 13 clks, in either Mode)
</PRE></TD></TR></TBODY></TABLE><BR><B>40002B4h - NDS9 - SQRT_RESULT - 32bit - 
Square Root Result (R/W?)</B><BR><B>40002B8h - NDS9 - SQRT_PARAM - 64bit - 
Square Root Parameter Input (R/W)</B><BR>Unsigned 64bit parameter, and unsigned 
32bit result.<BR><BR><B>Notes</B><BR>Push all DIV/SQRT values (parameters, 
control, and result registers) when using DIV/SQRT registers on interrupt 
level.<BR>The NDS9 and NDS7 BIOSes additionally contain software based division 
and square root functions, which are NOT using above hardware registers (even 
the NDS9 functions are raw software).<BR>The Div/Sqrt timings are probably 
counted in 33.51MHz units?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsinterprocesscommunicationipc></A><FONT size=+2>&nbsp;DS 
      Inter Process Communication (IPC)</FONT></TD></TR></TBODY></TABLE><BR>Allows to 
exchange status information between ARM7 and ARM9 CPUs.<BR>The register can be 
accessed simultaneously by both CPUs (without violating access permissions, and 
without generating waitstates at either side).<BR><BR><B>4000180h - NDS9/NDS7 - 
IPCSYNC - IPC Synchronize Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Dir  Expl.
  0-3   R    Data input from IPCSYNC Bit8-11 of remote CPU (00h..0Fh)
  4-7   -    Not used
  8-11  R/W  Data output to IPCSYNC Bit0-3 of remote CPU   (00h..0Fh)
  12    -    Not used
  13    W    Send IRQ to remote CPU      (0=None, 1=Send IRQ)
  14    R/W  Enable IRQ from remote CPU  (0=Disable, 1=Enable)
  15-31 -    Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000184h - NDS9/NDS7 - IPCFIFOCNT - IPC 
Fifo Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Dir  Expl.
  0     R    Send Fifo Empty Status      (0=Not Empty, 1=Empty)
  1     R    Send Fifo Full Status       (0=Not Full, 1=Full)
  2     R/W  Send Fifo Empty IRQ         (0=Disable, 1=Enable)
  3     W    Send Fifo Clear             (0=Nothing, 1=Flush Send Fifo)
  4-7   -    Not used
  8     R    Receive Fifo Empty          (0=Not Empty, 1=Empty)
  9     R    Receive Fifo Full           (0=Not Full, 1=Full)
  10    R/W  Receive Fifo Not Empty IRQ  (0=Disable, 1=Enable)
  11-13 -    Not used
  14    R/W  Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)
  15    R/W  Enable Send/Receive Fifo    (0=Disable, 1=Enable)
  16-31 -    Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>4000188h - NDS9/NDS7 - IPCFIFOSEND - IPC 
Send Fifo (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-31  Send Fifo Data (max 16 words; 64bytes)
</PRE></TD></TR></TBODY></TABLE><BR><B>4100000h - NDS9/NDS7 - IPCFIFORECV - IPC 
Receive Fifo (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-31  Receive Fifo Data (max 16 words; 64bytes)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dskeypad></A><FONT size=+2>&nbsp;DS 
Keypad</FONT></TD></TR></TBODY></TABLE><BR>For the GBA-buttons: Same as GBA, 
both ARM7 and ARM9 have keyboard input registers, and each its own keypad IRQ 
control register.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbakeypadinput">GBA Keypad 
Input</A><BR><BR>For Touchscreen (and Microphone) inputs, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dstouchscreencontrollertsc">DS Touch 
Screen Controller (TSC)</A><BR><BR><B>4000136h - NDS7 - EXTKEYIN - Key X/Y Input 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0      Button X     (0=Pressed, 1=Released)
  1      Button Y     (0=Pressed, 1=Released)
  3      DEBUG button (0=Pressed, 1=Released/None such)
  6      Pen down     (0=Pressed, 1=Released/Disabled)
  7      Hinge/folded (0=Open, 1=Closed)
  2,4,5  Unknown / set
  8..15  Unknown / zero
</PRE></TD></TR></TBODY></TABLE>The Hinge stuff is a magnetic sensor somewhere 
underneath of the Start/Select buttons, it will be triggered by the magnet field 
from the right speaker when the console is closed. The hinge generates an 
interrupt request (there seems to be no way to disable this, unlike as for all 
other IRQ sources), however, the interrupt execution can be disabled in IE 
register (as for other IRQ sources).<BR>The Pen Down is the /PENIRQ signal from 
the Touch Screen Controller (TSC), if it is enabled in the TSC control register, 
then it will notify the program when the screen pressed, the program should then 
read data from the TSC (if there's no /PENIRQ then doing unneccassary TSC reads 
would just waste CPU power). However, the user may release the screen before the 
program performs the TSC read, so treat the screen as not pressed if you get 
invalid TSC values (even if /PENIRQ was LOW).<BR>Not sure if the TSC /PENIRQ is 
actually triggering an IRQ in the NDS?<BR>The Debug Button should be connected 
to R03 and GND (on original NDS, R03 is the large soldering point between the 
SL1 jumper and the VR1 potentiometer) (there is no R03 signal visible on the 
NDS-Lite board).<BR>Interrupts are reportedly not supported for X,Y 
buttons.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsabsentlinkport></A><FONT size=+2>&nbsp;DS Absent Link 
      Port</FONT></TD></TR></TBODY></TABLE><BR>The DS doesn't have a Serial Link Port 
Socket, however, internally, the NDS7 contains the complete set of Serial I/O 
Ports, as contained in the GBA:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacommunicationports">GBA 
Communication Ports</A><BR><BR>In GBA mode, the ports are working as on real GBA 
(as when no cable is connected). In NDS mode, the ports are even containing some 
additional bits:<BR><BR><B>NDS7 SIO Bits (according to an early I/O map from 
Nintendo)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS7 4000128h SIOCNT   Bit15 "CKUP"  New Bit in NORMAL/MULTI/UART mode (R/W)
  NDS7 4000128h SIOCNT   Bit14 "N/A"   Removed IRQ Bit in UART mode (?)
  NDS7 400012Ah SIOCNT_H Bit14 "TFEMP" New Bit (R/W)
  NDS7 400012Ah SIOCNT_H Bit15 "RFFUL" New Bit (always zero?)
  NDS7 400012Ch SIOSEL   Bit0  "SEL"   New Bit (always zero?)
  NDS7 4000140h JOYCNT   Bit7  "MOD"   New Bit (R/W)
</PRE></TD></TR></TBODY></TABLE>The "CKUP" bit duplicates the internal clock 
transfer rate (selected in SIOCNT.1) (tested in normal mode) (probably works 
also in multi/uart mode?).<BR><BR><B>NDS9 SIO Bits (according to an early I/O 
map from Nintendo)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  NDS9 4000120h SIODATA32 Bit0-31 Data            (always zero?)
  NDS9 4000128h SIOCNT    Bit2    "TRECV" New Bit (always zero?)
  NDS9 4000128h SIOCNT    Bit3    "TSEND" New Bit (always zero?)
  NDS9 400012Ch SIOSEL    Bit0    "SEL"   New Bit (always zero?)
</PRE></TD></TR></TBODY></TABLE>Not sure if these ports really exist in the 
release-version, or if it's been prototype stuff?<BR><BR><B>RCNT</B><BR>RCNT 
(4000134h) should be set to 80xxh (general purpose mode) before accessing 
EXTKEYIN (4000136h) or RTC (4000138h). No idea why (except when using 
RTC/SI-interrupt).<BR><BR><B>DS Serial Port</B><BR>The SI line is labeled "INT" 
on the NDS mainboard, it is connected to Pin 1 of the RTC chip (ie. the /INT 
interrupt pin).<BR>I have no idea where to find SO, SC, and SD. I've written a 
test proggy that pulsed all four RCNT bits - but all I could find was the SI 
signal. However, the BIOS contains some code that uses SIO normal mode transfers 
(for the debug version), so at least SI, SO, SC should exist...?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsrealtimeclockrtc></A><FONT size=+2>&nbsp;DS Real-Time Clock 
      (RTC)</FONT></TD></TR></TBODY></TABLE><BR>Seiko Instruments Inc. S-35180 
(compatible with S-35190A)<BR>Miniature 8pin RTC with 3-wire serial 
bus<BR><BR><B>4000138h - NDS7 - Real Time Clock Register</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Expl.
  0    Data I/O   (0=Low, 1=High)
  1    Clock Out  (0=Low, 1=High)
  2    Select Out (0=Low, 1=High/Select)
  4    Data  Direction  (0=Read, 1=Write)
  5    Clock Direction  (should be 1=Write)
  6    Select Direction (should be 1=Write)
  3,8-11   Unused I/O Lines
  7,12-15  Direction for Bit3,8-11 (usually 0)
</PRE></TD></TR></TBODY></TABLE><BR><B>Serial Transfer 
Flowchart</B><BR>Chipselect and Command/Parameter Sequence:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Init CS=LOW and /SCK=HIGH, and wait at least 1us
  Switch CS=HIGH, and wait at least 1us
  Send the Command byte (see bit-transfer below)
  Send/receive Parameter byte(s) associated with the command (see below)
  Switch CS to LOW
</PRE></TD></TR></TBODY></TABLE>Bit transfer (repeat 8 times per cmd/param byte) 
(bits transferred LSB first):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Output /SCK=LOW and SIO=databit (when writing), then wait at least 5us
  Output /SCK=HIGH, wait at least 5us, then read SIO=databit (when reading)
  In either direction, data is output on (or immediately after) falling edge.
</PRE></TD></TR></TBODY></TABLE>Ideally, &lt;both&gt; commands and parameters 
should be transmitted LSB-first (unlike the original Seiko document, which 
recommends LSB-first for data, and MSB-first for commands).<BR><BR><B>Command 
Register</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Command Register
    Fwd  Rev
    0-3  7-4 Fixed Code (must be 06h = 0110b) (same for Fwd and Rev)
    4-6  3-1 Command
             Fwd Rev Parameter bytes (read/write access)
             0   0   1 byte, status register 1
             4   1   1 byte, status register 2
             2   2   7 bytes, date &amp; time (year,month,day,day_of_week,hour,minute, second)
             6   3   3 bytes, time (hour,minute,second)
             1*  4*  1 byte, int1, frequency duty setting
             1*  4*  3 bytes, int1, alarm time 1 (day_of_week, hour, minute)
             5   5   3 bytes, int2, alarm time 2 (day_of_week, hour, minute)
             3   6   1 byte, clock adjustment register
             7   7   1 byte, free register
    7    0   Parameter Read/Write Access (0=Write, 1=Read)
</PRE></TD></TR></TBODY></TABLE>* INT1: Type and number of parameters depend on 
INT1 setting in stat reg2.<BR>The "Fwd" bit numbers and command values for 
LSB-first command transfers (ie. both commands and parameters use the same 
bit-order).<BR>The "Rev" numbers/values are for MSB-first command transfers (ie. 
commands using opposite bit-order than parameters, as being suggested by 
Seiko).<BR><BR><B>Control and Status Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Status Register 1
    0   W   Reset                (0=Normal, 1=Reset)
    1   R/W 12/24 hour mode      (0=12 hour, 1=24 hour)
    2-3 R/W General purpose bits
    4   R   Interrupt 1 Flag (1=Yes)                      ;auto-cleared on read
    5   R   Interrupt 2 Flag (1=Yes)                      ;auto-cleared on read
    6   R   Power Low Flag (0=Normal, 1=Power is/was low) ;auto-cleared on read
    7   R   Power Off Flag (0=Normal, 1=Power was off)    ;auto-cleared on read
    Power off indicates that the battery was removed or fully discharged,
    all registers are reset to 00h (or 01h), and must be re-initialized.
  Status Register 2
    0-3 R/W INT1 Mode/Enable
            0000b Disable
            0x01b Selected Frequency steady interrupt
            0x10b Per-minute edge interrupt
            0011b Per-minute steady interrupt 1 (duty 30.0 secomds)
            0100b Alarm 1 interrupt
            0111b Per-minute steady interrupt 2 (duty 0.0079 secomds)
            1xxxb 32kHz output
    4-5 R/W General purpose bits
    6   R/W INT2 Enable
            0b    Disable
            1b    Alarm 2 interrupt
    7   R/W Test Mode (0=Normal, 1=Test, don't use) (cleared on Reset)
  Clock Adjustment Register (to compensate oscillator inaccuracy)
    0-7 R/W Adjustment (00h=Normal, no adjustment)
  Free Register
    0-7 R/W General purpose bits
</PRE></TD></TR></TBODY></TABLE><BR><B>Date Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Year Register
    0-7 R/W Year     (BCD 00h..99h = 2000..2099)
  Month Register
    0-4 R/W Month    (BCD 01h..12h = January..December)
    5-7 -   Not used (always zero)
  Day Register
    0-5 R/W Day      (BCD 01h..28h,29h,30h,31h, range depending on month/year)
    6-7 -   Not used (always zero)
  Day of Week Register (septenary counter)
    0-2 R/W Day of Week (00h..06h, custom assignment, usually 0=Monday?)
    3-7 -   Not used (always zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>Time Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Hour Register
    0-5 R/W Hour     (BCD 00h..23h in 24h mode, or 00h..11h in 12h mode)
    6   *   AM/PM    (0=AM before noon, 1=PM after noon)
            * 24h mode: AM/PM flag is read only (PM=1 if hour = 12h..23h)
            * 12h mode: AM/PM flag is read/write-able
            * 12h mode: Observe that 12 o'clock is defined as 00h (not 12h)
    7   -   Not used (always zero)
  Minute Register
    0-6 R/W Minute   (BCD 00h..59h)
    7   -   Not used (always zero)
  Second Register
    0-6 R/W Minute   (BCD 00h..59h)
    7   -   Not used (always zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>Alarm 1 and Alarm 2 Registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Alarm1 and Alarm2 Day of Week Registers (INT1 and INT2 each)
    0-2 R/W Day of Week (00h..06h)
    3-6 -   Not used (always zero)
    7   R/W Compare Enable (0=Alarm every day, 1=Alarm only at specified day)
  Alarm1 and Alarm2 Hour Registers (INT1 and INT2 each)
    0-5 R/W Hour     (BCD 00h..23h in 24h mode, or 00h..11h in 12h mode)
    6   R/W AM/PM    (0=AM, 1=PM) (must be correct even in 24h mode?)
    7   R/W Compare Enable (0=Alarm every hour, 1=Alarm only at specified hour)
  Alarm1 and Alarm2 Minute Registers (INT1 and INT2 each)
    0-6 R/W Minute   (BCD 00h..59h)
    7   R/W Compare Enable (0=Alarm every min, 1=Alarm only at specified min)
  Selected Frequency Steady Interrupt Register (INT1 only) (when Stat2/Bit2=0)
    0   R/W Enable 1Hz Frequency  (0=Disable, 1=Enable)
    1   R/W Enable 2Hz Frequency  (0=Disable, 1=Enable)
    2   R/W Enable 4Hz Frequency  (0=Disable, 1=Enable)
    3   R/W Enable 8Hz Frequency  (0=Disable, 1=Enable)
    4   R/W Enable 16Hz Frequency (0=Disable, 1=Enable)
            The signals are ANDed when two or more frequencies are enabled,
            ie. the /INT signal gets LOW when either of the signals is LOW.
    5-7 R/W General purpose bits
</PRE></TD></TR></TBODY></TABLE>Note: There is only one register shared as 
"Selected Frequency Steady Interrupt" (accessed as single byte parameter when 
Stat2/Bit2=0) and as "Alarm1 Minute" (accessed as 3rd byte of 3-byte parameter 
when Stat2/Bit2=1), changing either value will also change the other 
value.<BR><BR><B>Interrupt</B><BR>There's only one /INT signal, shared for both 
INT1 and INT2.<BR>In the NDS, it is connected to the SI-input of the SIO unit 
(and so, also shared with SIO interrupts). To enable the interrupt, RCNT should 
be set to 8144h (Bit14-15=General Purpose mode, Bit8=SI Interrupt Enable, 
Bit6,2=SI Output/High).<BR>Not sure why Output/High... maybe as pullup... 
however, it seems to be working also as Input... ie. 
RCNT=8100h.<BR><BR><B>Pin-Outs</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1 /INT      8 VDD
  2 XOUT      7 SIO
  3 XIN       6 /SCK
  4 GND       5 CS
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsserialperipheralinterfacebusspi></A><FONT size=+2>&nbsp;DS 
      Serial Peripheral Interface Bus 
(SPI)</FONT></TD></TR></TBODY></TABLE><BR><B>Serial Peripheral Interface 
Bus</B><BR>SPI Bus is a 4-wire (Data In, Data Out, Clock, and Chipselect) serial 
bus.<BR>The NDS supports the following SPI devices (each with its own 
chipselect).<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareserialflashmemory">DS 
Firmware Serial Flash Memory</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dstouchscreencontrollertsc">DS Touch 
Screen Controller (TSC)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dspowermanagement">DS Power 
Management</A><BR><BR><B>40001C0h - NDS7 - SPICNT - SPI Bus Control/Status 
Register</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Baudrate (0=4MHz/Firmware, 1=2MHz/Touchscr, 2=1MHz/Powerman., 3=512KHz)
  2-6   Not used            (Zero)
  7     Busy Flag           (0=Ready, 1=Busy) (presumably Read-only)
  8-9   Device Select       (0=Powerman., 1=Firmware, 2=Touchscr, 3=Reserved)
  10    Transfer Size       (0=8bit/Normal, 1=16bit/Bugged)
  11    Chipselect Hold     (0=Deselect after transfer, 1=Keep selected)
  12-13 Not used            (Zero)
  14    Interrupt Request   (0=Disable, 1=Enable)
  15    SPI Bus Enable      (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE>The "Hold" flag should be cleared BEFORE 
transferring the LAST data unit, the chipselect will be then automatically 
cleared after the transfer, the program should issue a WaitByLoop(3) manually 
AFTER the LAST transfer.<BR><BR><B>40001C2h - NDS7 - SPIDATA - SPI Bus 
Data/Strobe Register (R/W)</B><BR>The SPI transfer is started on writing to this 
register, so one must &lt;write&gt; a dummy value (should be zero) even when 
intending to &lt;read&gt; from SPI bus.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Data
  8-15  Not used (always zero, even in bugged-16bit mode)
</PRE></TD></TR></TBODY></TABLE>During transfer, the Busy flag in SPICNT is set, 
and the written SPIDATA value is transferred to the device (via output line), 
simultaneously data is received (via input line). Upon transfer completion, the 
Busy flag goes off (with optional IRQ), and the received value can be then read 
from SPIDATA, if desired.<BR><BR><B>Notes/Glitches</B><BR>SPICNT Bits 12,13 
appear to be unused (always zero), although the BIOS (attempts to) set Bit13=1, 
and Bit12=Bit11 when accessing the firmware.<BR>The SPIDATA register is 
restricted to 8bit, so that only each 2nd byte will appear in SPIDATA when 
attempting to use the bugged-16bit mode.<BR><BR><B>Cartridge Backup Auxiliar SPI 
Bus</B><BR>The NDS Cartridge Slot uses a separate SPI bus (with other I/O 
Ports), see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgebackup">DS Cartridge 
Backup</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dstouchscreencontrollertsc></A><FONT size=+2>&nbsp;DS Touch 
      Screen Controller (TSC)</FONT></TD></TR></TBODY></TABLE><BR><B>Texas Instruments 
TSC2046 (NDS)</B><BR><B>Asahi Kasei Microsystems AK4148AVT (NDS-Lite)</B><BR>The 
Touch Screen Controller (for lower LCD screen) is accessed via SPI bus,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsserialperipheralinterfacebusspi">DS 
Serial Peripheral Interface Bus (SPI)</A><BR><BR><B>Control Byte (transferred 
MSB first)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1  Power Down Mode Select
  2    Reference Select (0=Differential, 1=Single-Ended)
  3    Conversion Mode  (0=12bit, max CLK=2MHz, 1=8bit, max CLK=3MHz)
  4-6  Channel Select   (0-7, see below)
  7    Start Bit (Must be set to access Control Byte)
</PRE></TD></TR></TBODY></TABLE><BR><B>Channel</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0 Temperature 0 (requires calibration, step 2.1mV per 1'C accuracy)
  1 Touchscreen Y-Position  (somewhat 0B0h..F20h, or FFFh=released)
  2 Battery Voltage         (not used, connected to GND in NDS, always 000h)
  3 Touchscreen Z1-Position (diagonal position for pressure measurement)
  4 Touchscreen Z2-Position (diagonal position for pressure measurement)
  5 Touchscreen X-Position  (somewhat 100h..ED0h, or 000h=released)
  6 AUX Input               (connected to Microphone in the NDS)
  7 Temperature 1 (difference to Temp 0, without calibration, 2'C accuracy)
</PRE></TD></TR></TBODY></TABLE>All channels can be accessed in Single-Ended 
mode.<BR>In differential mode, only channel 1,3,4,5 (X,Z1,Z2,Y) can be 
accessed.<BR>On AK4148AVT, channel 6 (AUX) is split into two separate channels, 
IN1 and IN2, separated by Bit2 (Reference Select). IN1 is selected when Bit2=1, 
IN2 is selected when Bit2=0 (despite of the Bit2 settings, both IN1 and IN2 are 
using single ended more). On the NDS-Lite, IN1 connects to the mircrophone (as 
on original NDS), and the new IN2 input is simply wired to VDD3.3 (which is 
equal the the external VREF voltage, so IN2 is always FFFh).<BR><BR><B>Power 
Down Mode</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Mode /PENIRQ   VREF  ADC   Recommended use
  0    Enabled   Auto  Auto  Differential Mode (Touchscreen, Penirq)
  1    Disabled  Off   On    Single-Ended Mode (Temperature, Microphone)
  2    Enabled   On    Off   Don't use
  3    Disabled  On    On    Don't use
</PRE></TD></TR></TBODY></TABLE>Allows to enable/disable the /PENIRQ output, the 
internal reference voltage (VREF), and the Analogue-Digital Converter.<BR>For 
AK4148AVT, Power Down modes are slightly different (among others, /PENIRQ is 
enabled in Mode 0..2).<BR><BR><B>Reference Voltage (VREF)</B><BR>VREF is used as 
reference voltage in single ended mode, at 12bit resolution one ADC step equals 
to VREF/4096. The TSC generates an internal VREF of 2.5V (+/-0.05V), however, 
the NDS uses as external VREF of 3.33V (sinks to 3.31V at low battery charge), 
the external VREF is always enabled, no matter if internal VREF is on or off. 
Power Down Mode 1 disables the internal VREF, which may reduce power consumption 
in single ended mode. After conversion, Power Down Mode 0 should be restored to 
re-enable the Penirq signal.<BR><BR><B>Sending the first Command after 
Chip-Select</B><BR>Switch chipselect low, then output the command byte (MSB 
first).<BR><BR><B>Reply Data</B><BR>The following reply data is received (via 
Input line) after the Command byte has been transferred: One dummy bit (zero), 
followed by the 8bit or 12bit conversion result (MSB first), followed by endless 
padding (zero).<BR>Note: The returned ADC value may become unreliable if there 
are longer delays between sending the command, and receiving the reply 
byte(s).<BR><BR><B>Sending further Commands during/after receiving Reply 
Data</B><BR>In general, the Output line should be LOW during the reply period, 
however, once when Data bit6 has been received (or anytime later), a new Command 
can be invoked (started by sending the HIGH-startbit, ie. Command bit7), 
simultanously, the remaining reply-data bits (bit5..0) can be received.<BR>In 
other words, the new command can be output after receiving 3 bits in 8bit mode 
(the dummy bit, and data bits 7..6), or after receiving 7 bits in 12bit mode 
(the dummy bit, and data bits 11..6).<BR>In practice, the NDS SPI register 
always transfers 8 bits at once, so that one would usually receive 8 bits 
(rather than above 3 or 7 bits), before outputting a new 
command.<BR><BR><B>Touchscreen Position</B><BR>Read the X and Y positions in 
12bit differential mode, then convert the touchscreen values (adc) to 
screen/pixel positions (scr), as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  scr.x = (adc.x-adc.x1) * (scr.x2-scr.x1) / (adc.x2-adc.x1) + (scr.x1-1)
  scr.y = (adc.y-adc.y1) * (scr.y2-scr.y1) / (adc.y2-adc.y1) + (scr.y1-1)
</PRE></TD></TR></TBODY></TABLE>The X1,Y1 and X2,Y2 calibration points are found 
in Firmware User Settings,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareusersettings">DS Firmware 
User Settings</A><BR>scr.x1,y1,x2,y2 are originated at 1,1 (converted to 0,0 by 
above formula).<BR><BR><B>Touchscreen Pressure</B><BR>To calculate the pressure 
resistance, in respect to X/Y/Z positions and X/Y plate resistances, either of 
below formulas can be used,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Rtouch = (Rx_plate*Xpos*(Z2pos/Z1pos-1))/4096
  Rtouch = (Rx_plate*Xpos*(4096/Z1pos-1)-Ry_plate*(1-Ypos))/4096
</PRE></TD></TR></TBODY></TABLE>The second formula requires less CPU load (as it 
doesn't require to measure Z2), the downside is that one must know both X and Y 
plate resistance (or at least their ratio). The first formula doesn't require 
that ratio, and so Rx_plate can be set to any value, setting it to 4096 results 
in<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  touchval = Xpos*(Z2pos/Z1pos-1)
</PRE></TD></TR></TBODY></TABLE>Of course, in that case, touchval is just a 
number, not a resistance in Ohms.<BR><BR><B>Touchscreen Notes</B><BR>It may be 
impossible to press locations close to the screen borders.<BR>When pressing two 
or more locations the TSC values will be somewhere in the middle of these 
locations.<BR>The TSC values may be garbage if the screen becomes newly pressed 
or released, to avoid invalid inputs: read TSC values at least two times, and 
ignore BOTH positions if ONE position was invalid.<BR><BR><B>Microphone / AUX 
Channel</B><BR>Observe that the microphone amplifier is switched off after power 
up, see:<BR><A href="http://nocash.emubase.de/gbatek.htm#dspowermanagement">DS 
Power Management</A><BR><BR><B>Temperature Calculation</B><BR>TP0 decreases by 
circa 2.1mV per degree Kelvin. The voltage difference between TP1 minus TP0 
increases by circa 0.39mV (1/2573 V) per degree Kelvin. At VREF=3.33V, one 12bit 
ADC step equals to circa 0.8mV (VREF/4096).<BR>Temperature can be calculated at 
best resolution when using the current TP0 value, and two calibration values (an 
ADC value, and the corresponding temperature in degrees kelvin):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  K = (CAL.TP0-ADC.TP0) * 0.4 + CAL.KELVIN
</PRE></TD></TR></TBODY></TABLE>Alternately, temperature can be calculated at 
rather bad resolution, but without calibration, by using the difference between 
TP1 and TP0:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  K = (ADC.TP1-ADC.TP0) * 8568 / 4096
</PRE></TD></TR></TBODY></TABLE>To convert Kelvin to other formats,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Celsius:     C = (K-273.15)
  Fahrenheit:  F = (K-273.15)*9/5+32
  Reaumur:     R = (K-273.15)*4/5
  Rankine:     X = (K)*9/5
</PRE></TD></TR></TBODY></TABLE>The Temperature Range for the TSC 2046 chip is 
-40'C..+85'C (for AK4181AVT only -20'C..+70'C). According to Nintendo, the DS 
should not be exposed to "extreme" heat or cold, the optimal battery charging 
temperature is specified as +10'C..+40'C.<BR>The original firmware does not 
support temperature calibration, calibration is supported by nocash firmware (if 
present). See Extended Settings,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareextendedsettings">DS 
Firmware Extended Settings</A><BR><BR><B>Pin-Outs</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>         ________
  VCC  1|o       |16 DCLK
  X+   2|        |15 /CS
  Y+   3|  TSC   |14 DIN
  X-   4|  2046  |13 BUSY
  Y-   5|        |12 DOUT
  GND  6|        |11 /PENIRQ
  VBAT 7|        |10 IOVDD
  AUX  8|________|9  VREF
</PRE></TD></TR></TBODY></TABLE><BR>For AK4181AVT, same pins as above, except 
that IOVDD replaced by the new IN2 input, the pin is wired to VDD3.3 (so IN2 is 
always equal to VREF, which is wired to VDD3.3, too) (and AUX is renamed to IN1, 
and is kept used for MIC input).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dspowermanagement></A><FONT size=+2>&nbsp;DS Power 
      Management</FONT></TD></TR></TBODY></TABLE><BR>The DS contains several Power 
Managment functions, some accessed via I/O ports, some accessed via SPI bus 
(described later on below).<BR><BR><B>4000304h - NDS9 - POWCNT1 - Graphics Power 
Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Enable Flag for both LCDs (0=Disable) (Prohibited, see notes)
  1     2D Graphics Engine A      (0=Disable) (Ports 008h-05Fh, Pal 5000000h)
  2     3D Rendering Engine       (0=Disable) (Ports 320h-3FFh)
  3     3D Geometry Engine        (0=Disable) (Ports 400h-6FFh)
  4-8   Not used
  9     2D Graphics Engine B      (0=Disable) (Ports 1008h-105Fh, Pal 5000400h)
  10-14 Not used
  15    Display Swap (0=Send Display A to Lower Screen, 1=To Upper Screen)
</PRE></TD></TR></TBODY></TABLE>Use SwapBuffers command once after enabling 
Rendering/Geometry Engine.<BR>Improper use of Bit0 may damage the 
hardware?<BR>When disabled, corresponding Ports become Read-only, corresponding 
(palette-) memory becomes read-only-zero-filled.<BR><BR><B>4000304h - NDS7 - 
POWCNT2 - Sound/Wifi Power Control Register (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Sound Speakers (0=Disable, 1=Enable) (Initial setting = 1)
  1     Wifi           (0=Disable, 1=Enable) (Initial setting = 0)
  2-31  Not used
</PRE></TD></TR></TBODY></TABLE>Note: Bit0 disables the internal Speaker only, 
headphones are not disabled.<BR>Bit1 disables Port 4000206h, and Ports 
4800000h-480FFFFh.<BR><BR><B>4000206h - NDS7 - WIFIWAITCNT - Wifi Waitstate 
Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-2   Wifi WS0 Control (0-7) (Ports 4800000h-4807FFFh)
  3-5   Wifi WS1 Control (0-7) (Ports 4808000h-480FFFFh)
  4-15  Not used (zero)
</PRE></TD></TR></TBODY></TABLE>This register is initialized by firmware on 
power-up, don't change.<BR>Note: WIFIWAITCNT can be accessed only when enabled 
in POWCNT2.<BR><BR><B>4000301h - NDS7 - HALTCNT - Low Power Mode Control 
(R/W)</B><BR>In Halt mode, the CPU is paused as long as (IE AND IF)=0.<BR>In 
Sleep mode, most of the hardware including sound and video are paused, this 
very-low-power mode could be used much like a screensaver.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-5   Not used (zero)
  6-7   Power Down Mode  (0=No function, 1=Enter GBA Mode, 2=Halt, 3=Sleep)
</PRE></TD></TR></TBODY></TABLE>The HALTCNT register should not be accessed 
directly. Instead, the BIOS Halt, Sleep, CustomHalt, IntrWait, or VBlankIntrWait 
SWI functions should be used.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#bioshaltfunctions">BIOS Halt 
Functions</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#armcp15systemcontrolcoprocessor">ARM 
CP15 System Control Coprocessor</A><BR>The NDS9 does not have a HALTCNT 
register, instead, the Halt function uses the co-processor opcode "mcr 
p15,0,r0,c7,c0,4" - this opcode locks up if interrupts are disabled via IME=0 
(unlike NDS7 HALTCNT method which doesn't check IME).<BR><BR><B>4000300h - 
NDS7/NDS9 - POSTFLG - BYTE - Post Boot Flag (R/W)</B><BR>The NDS7 and NDS9 post 
boot flags are usually set upon BIOS/Firmware boot completion, once when set the 
reset vector is redirected to the debug handler of Nintendo's hardware debugger. 
That allows the NDS7 debugger to capture accidental jumps to address 0, that 
appears to be a common problem with HLL-programmers, asm-coders know that (and 
why) they should not jump to 0.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0     Post Boot Flag (0=Boot in progress, 1=Boot completed)
  1     NDS7: Not used (always zero), NDS9: Bit1 is read-writeable
  2-7   Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>There are some write-restrictions: The NDS7 
register can be written to only from code executed in BIOS. Bit0 of both NDS7 
and NDS9 registers cannot be cleared (except by Reset) once when it is 
set.<BR><BR><B>Power Management Device - Mitsumi 3152A (NDS) / Mitsumi 3205B 
(NDS-LITE)</B><BR>The Power Management Device is accessed via SPI bus,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsserialperipheralinterfacebusspi">DS 
Serial Peripheral Interface Bus (SPI)</A><BR>To access the device, write the 
Index Register, then read or write the data register, and release the chipselect 
line when finished.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Index Register</B>
  Bit0-2 Register Select          (0..3) (0..4 for DS-Lite)
  Bit3-6 Not used
  Bit7   Register Direction       (0=Write, 1=Read)
<B>  Register 0 - Powermanagement Control (R/W)</B>
  Bit0   Sound Amplifier Enable   (0=Disable, 1=Enable)
         (Old-DS:  Disabled: Sound is very silent, but still audible)
         (DS-Lite: Disabled: Sound is NOT audible)
  Bit1   Sound Amplifier Mute     (0=Normal, 1=Mute) (Old-DS Only, not DS-Lite)
         (Old-DS:  Muted: Sound is NOT audible, that works only if Bit0=1)
         (DS-Lite: Not used, Bit1 is always zero)
  Bit2   Lower Backlight          (0=Disable, 1=Enable)
  Bit3   Upper Backlight          (0=Disable, 1=Enable)
  Bit4   Power LED Blink Enable   (0=Always ON, 1=Blinking OFF/ON)
  Bit5   Power LED Blink Speed    (0=Slow, 1=Fast) (only if Blink enabled)
  Bit6   DS System Power          (0=Normal, 1=Shut Down)
  Bit7   Not used                 (always 0)
<B>  Register 1 - Battery Status (R)</B>
  Bit0   Battery Power LED Status (0=Power Good/Green, 1=Power Low/Red)
  Bit1-7 Not used
<B>  Register 2 - Microphone Amplifier Control (R/W)</B>
  Bit0   Amplifier                (0=Disable, 1=Enable)
  Bit1-7 Not used                 (always 0)
<B>  Register 3 - Microphone Amplifier Gain Control (R/W)</B>
  Bit0-1 Gain                     (0..3=Gain 20, 40, 80, 160)
  Bit2-7 Not used                 (always 0)
<B>  Register 4 - DS-Lite Only - Backlight Levels/Power Source (R/W)</B>
  Bit0-1 Backlight Brightness (0..3=Low,Med,High,Max)   (R/W)
         (when bit2+3 are both set, then reading bit0-1 always returns 3)
  Bit2   Force Max Brightness when Bit3=1 (0=No, 1=Yes) (R/W)
  Bit3   External Power Present           (0=No, 1=Yes) (Read-Only)
  Bit4-7 Unknown (Always 4) (Read-Only)
</PRE></TD></TR></TBODY></TABLE>On Old-DS, registers 4..7Fh are mirrors of 0..3. 
On DS-Lite, registers 5,6,7 are mirrors of 4, register 8..7Fh are mirrors of 
0-7.<BR><BR><B>Backlight Dimming / Backlight caused Shut-Down(s)</B><BR>The 
above bits are essentially used to switch Backlights on or off. However, there a 
number of strange effects. Backlight dimming is possible by pulse width 
modulation, ie. by using a timer interrupt to issue pulse widths of N% ON, and 
100-N% OFF. Too long pulses are certainly resulting in flickering. Too short 
pulses are ignored, the backlights will remain OFF, even if the ON and OFF 
pulses are having the same length. Much too short pulses cause the power supply 
to shut-down; after changing the backlight state, further changes must not occur 
within the next (circa) 2500 clock cycles. The mainboard can be operated without 
screens &amp; backlights connected, however, if so, the power supply will 
shut-down as soon as backlights are enabled.<BR>That method works also on the 
DS-Lite, allowing to use smoother fade in/out effects as when using the five 
"hardware" levels (Off,Low,Med,High,Max).<BR><BR><B>Memory Power Down 
Functions</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmainmemorycontrol">DS Main Memory 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareserialflashmemory">DS 
Firmware Serial Flash Memory</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsmainmemorycontrol></A><FONT size=+2>&nbsp;DS Main Memory 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>Main Memory</B><BR>The DS Main 
Memory is 2Mx16bit (4MByte), 1.8V Pseudo SRAM (PSRAM); all Dynamic RAM refresh 
is handled internally, the chip doesn't require any external refresh signals, 
and alltogether behaves like Static RAM. Non-sequential access time is 70ns, 
sequential (burst) access time is 12ns.<BR><BR><B>Main Memory Control</B><BR>The 
memory chips contain built-in Control functions, which can be accessed via Port 
27FFFFEh and/or by EXMEMCNT Bit 14. Nintendo is using at least two different 
types of memory chips in DS consoles, Fujitsu 82DBS02163C-70L, and ST 
M69AB048BL70ZA8, both appear to have different control mechanisms, other chips 
(with 8MB size) are used in the semi-professional DS hardware debuggers, and 
further chips may be used in future, so using the memory control functions may 
lead into compatibitly problems.<BR><BR><B>Power Consumption / Power 
Control</B><BR>Power Consumption during operation (read/write access) is 
somewhat 30mA, in standby mode (no read/write access) consumption is reduced to 
100uA.<BR>Furthermore, a number of power-down modes are supported: In "Deep" 
Power Down mode the refresh is fully disabled, consumption is 10uA (and all data 
will be lost), in "Partial" Power Down modes only fragment of memory is 
refreshed, for smallest fragments, consumption goes to down to circa 50uA. The 
chip cannot be accessed while it is in Deep or Partial Power Down 
mode.<BR><BR><B>Fujitsu 82DBS02163C-70L</B><BR>The Configuration Register (CR) 
can be written to by the following sequence:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LDRH R0,[27FFFFEh]      ;read one value
  STRH R0,[27FFFFEh]      ;write should be same value as above
  STRH R0,[27FFFFEh]      ;write should be same value as above
  STRH R0,[27FFFFEh]      ;write any value
  STRH R0,[27FFFFEh]      ;write any value
  LDRH R0,[2400000h+CR*2] ;read, address-bits are defining new CR value
</PRE></TD></TR></TBODY></TABLE>Do not access any other Main Memory addresses 
during above sequence (ie. disable interrupts, and do not execute the sequence 
by code located in Main Memory). The CR value is write-only. The CR bits 
are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit    Expl.
  0-6    Reserved         (Must be 7Fh)
  7      Write Control
           0=WE Single Clock Pulse Control without Write Suspend Function
           1=WE Level Control with Write Suspend Function)
          Burst Read/Single Write is not supported at WE Single Clock Mode.
  8      Reserved         (Must be 1)
  9      Valid Clock Edge (0=Falling Edge, 1=Rising Edge)
  10     Single Write     (0=Burst Read/Burst Write, 1=Burst Read/Single Write)
  11     Burst Sequence   (0=Reserved, 1=Sequential)
  12-14  Read Latency     (1=3 clocks, 2=4 clocks, 3=5 clocks, other=Reserved)
  15     Mode
           0=Synchronous:  Burst Read, Burst Write
           1=Asynchronous: Page Read, Normal Write
          In Mode 1 (Async), only the Partial Size bits are used,
          all other bits, CR bits 0..18, must be "1".
  16-18  Burst Length     (2=8 Words, 3=16Words, 7=Continous, other=Reserved)
  19-20  Partial Size     (0=1MB, 1=512KB, 2=Reserved, 3=Deep/0 bytes)
</PRE></TD></TR></TBODY></TABLE>The Power Down mode is entered by setting 
CE2=LOW, this can be probably done by setting EXMEMCNT Bit14 to 
zero.<BR><BR><B>ST Microelectronics M69AB048BL70ZA8</B><BR>The chip name decodes 
as PSRAM (M96), Asynchronous (A), 1.8V Burst (B), 2Mx16 (048), Two Chip Enables 
(B), Low Leakage (L), 70ns (70), Package (ZA), -30..+85'C (8).<BR>There are 
three data sheets for different PSRAM chips available at www.st.com 
(unfortunately none for M69AB048BL70ZA8), each using different memory control 
mechanisms.<BR><BR><B>NDS9 BIOS</B><BR>The NDS9 BIOS contains the following Main 
Memory initialization code, that method doesn't match up with any ST (nor 
Fujitsu) data sheets that I've seen. At its best, it looks like a strange (and 
presumably non-functional) mix-up of different ST control methods.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  STRH 2000h,[4000204h]
  LDRH R0,[27FFFFEh]
  STRH R0,[27FFFFEh]
  STRH R0,[27FFFFEh]
  STRH FFDFh,[27FFFFEh]
  STRH E732h,[27FFFFEh]
  LDRH R0,[27E57FEh]
  STRH 6000h,[4000204h]
</PRE></TD></TR></TBODY></TABLE>In the above BIOS code, EXMEMCNT.14 appears to 
be used to unlock the control register. However, the NDS Firmware appears to use 
EXMEMCNT.14 to switch Main Memory into Power Down mode before entering GBA 
mode.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgesencryptionfirmware></A><FONT size=+2>&nbsp;DS 
      Cartridges, Encryption, 
Firmware</FONT></TD></TR></TBODY></TABLE><BR><B>Cartridges</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeheader">DS Cartridge 
Header</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgesecurearea">DS Cartridge 
Secure Area</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeicontitle">DS Cartridge 
Icon/Title</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeprotocol">DS Cartridge 
Protocol</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgebackup">DS Cartridge 
Backup</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeioports">DS Cartridge I/O 
Ports</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgenitroromfilesystem">DS 
Cartridge NitroROM File System</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgepassmepassthrough">DS 
Cartridge PassMe/PassThrough</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgegbaslot">DS Cartridge GBA 
Slot</A><BR><BR><B>Add-Ons</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartrumblepak">DS Cart Rumble 
Pak</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dscartunknownaddons">DS 
Cart Unknown Add-Ons</A><BR><BR><B>Special Cartridges</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartcheatactionreplayds">DS Cart 
Cheat Action Replay DS</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartcheatcodebreakerds">DS Cart 
Cheat Codebreaker DS</A><BR><BR><B>Encryption</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsencryptionbygamecodeidcodekey1">DS 
Encryption by Gamecode/Idcode (KEY1)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsencryptionbyrandomseedkey2">DS 
Encryption by Random Seed (KEY2)</A><BR><BR><B>Firmware</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareserialflashmemory">DS 
Firmware Serial Flash Memory</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareheader">DS Firmware 
Header</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareusersettings">DS Firmware 
User Settings</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareextendedsettings">DS 
Firmware Extended Settings</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgeheader></A><FONT size=+2>&nbsp;DS Cartridge 
      Header</FONT></TD></TR></TBODY></TABLE><BR><B>Header Overview (loaded from ROM 
Addr 0 to Main RAM 27FFE00h on Power-up)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Address Bytes Expl.
  000h    12    Game Title  (Uppercase ASCII, padded with 00h)
  00Ch    4     Gamecode    (Uppercase ASCII, NTR-&lt;code&gt;)        (0=homebrew)
  010h    2     Makercode   (Uppercase ASCII, eg. "01"=Nintendo) (0=homebrew)
  012h    1     Unitcode    (00h=Nintendo DS)
  013h    1     Encryption Seed Select (00..07h, usually 00h)
  014h    1     Devicecapacity         (Chipsize = 128KB SHL nn) (eg. 7 = 16MB)
  015h    9     Reserved           (zero filled)
  01Eh    1     ROM Version        (usually 00h)
  01Fh    1     Autostart (Bit2: Skip "Press Button" after Health and Safety)
                (Also skips bootmenu, even in Manual mode &amp; even Start pressed)
  020h    4     ARM9 rom_offset    (4000h and up, align 1000h)
  024h    4     ARM9 entry_address (2000000h..23BFE00h)
  028h    4     ARM9 ram_address   (2000000h..23BFE00h)
  02Ch    4     ARM9 size          (max 3BFE00h) (3839.5KB)
  030h    4     ARM7 rom_offset    (8000h and up)
  034h    4     ARM7 entry_address (2000000h..23BFE00h, or 37F8000h..3807E00h)
  038h    4     ARM7 ram_address   (2000000h..23BFE00h, or 37F8000h..3807E00h)
  03Ch    4     ARM7 size          (max 3BFE00h, or FE00h) (3839.5KB, 63.5KB)
  040h    4     File Name Table (FNT) offset
  044h    4     File Name Table (FNT) size
  048h    4     File Allocation Table (FAT) offset
  04Ch    4     File Allocation Table (FAT) size
  050h    4     File ARM9 overlay_offset
  054h    4     File ARM9 overlay_size
  058h    4     File ARM7 overlay_offset
  05Ch    4     File ARM7 overlay_size
  060h    4     Port 40001A4h setting for normal commands (usually 00586000h)
  064h    4     Port 40001A4h setting for KEY1 commands   (usually 001808F8h)
  068h    4     Icon_title_offset (0=None) (8000h and up)
  06Ch    2     Secure Area Checksum, CRC-16 of [ [20h]..7FFFh]
  06Eh    2     Secure Area Loading Timeout (usually 051Eh)
  070h    4     ARM9 Auto Load List RAM Address (?)
  074h    4     ARM7 Auto Load List RAM Address (?)
  078h    8     Secure Area Disable (by encrypted "NmMdOnly") (usually zero)
  080h    4     Total Used ROM size (remaining/unused bytes usually FFh-padded)
  084h    4     ROM Header Size (4000h)
  088h    38h   Reserved (zero filled)
  0C0h    9Ch   Nintendo Logo (compressed bitmap, same as in GBA Headers)
  15Ch    2     Nintendo Logo Checksum, CRC-16 of [0C0h-15Bh], fixed CF56h
  15Eh    2     Header Checksum, CRC-16 of [000h-15Dh]
  160h    4     Debug rom_offset   (0=none) (8000h and up)       ;only if debug
  164h    4     Debug size         (0=none) (max 3BFE00h)        ;version with
  168h    4     Debug ram_address  (0=none) (2400000h..27BFE00h) ;SIO and 8MB
  16Ch    4     Reserved (zero filled) (transferred, and stored, but not used)
  170h    90h   Reserved (zero filled) (transferred, but not stored in RAM)
</PRE></TD></TR></TBODY></TABLE><BR>For more info about CRC-16, see description 
of GetCRC16 BIOS function,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#biosmiscfunctions">BIOS Misc 
Functions</A><BR>For the Logo checksum, the BIOS verifies only [15Ch]=CF56h, it 
does NOT verify the actual data at [0C0h-15Bh] (nor it's checksum), however, the 
data is verified by the firmware.<BR><BR>Secure Area Loading Timeout (usually 
X=051Eh) used to initialize timer counter to (0-((X AND 3FFFh)+2)). (In case of 
Header checksum error it is ANDed with 1FFFh instead of 3FFFh, no idea 
why).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgesecurearea></A><FONT size=+2>&nbsp;DS Cartridge 
      Secure Area</FONT></TD></TR></TBODY></TABLE><BR>The Secure Area is located in 
ROM at 4000h..7FFFh, it can contain normal program code and data, however, it 
can be used only for ARM9 boot code, it cannot be used for ARM7 boot code, 
icon/title, filesystem, or other data.<BR><BR><B>Secure Area Size</B><BR>The 
Secure Area exists if the ARM9 boot code ROM source address (src) is located 
within 4000h..7FFFh, if so, it will be loaded (by BIOS via KEY1 encrypted 
commands) in 4K portions, starting at src, aligned by 1000h, up to address 
7FFFh. The secure area size if thus 8000h-src, regardless of the ARM9 boot code 
size entry in header.<BR>Note: The BIOS silently skips any NDS9 bootcode at 
src&lt;4000h.<BR>Cartridges with src&gt;=8000h do not have a secure 
area.<BR><BR><B>Secure Area ID</B><BR>The first 8 bytes of the secure area are 
containing the Secure Area ID, the ID is required (verified by BIOS boot code), 
the ID value changes during boot process:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Value                Expl.
  "encryObj"           raw ID before encryption (raw ROM-image)
  (encrypted)          encrypted ID after encryption (encrypted ROM-image)
  "encryObj"           raw ID after decryption (verified by BIOS boot code)
  E7FFDEFFh,E7FFDEFFh  destroyed ID (overwritten by BIOS after verify)
</PRE></TD></TR></TBODY></TABLE>If the decrypted ID does match, then the BIOS 
overwrites the first 8 bytes by E7FFDEFFh-values (ie. only the ID is destroyed). 
If the ID doesn't match, then the first 800h bytes (2K) are overwritten by 
E7FFDEFFh-values.<BR><BR><B>Secure Area First 2K Encryption/Content</B><BR>The 
first 2K of the Secure Area (if it exists) are KEY1 encrypted. In official 
games, this 2K region contains data like so (in decrypted form):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  000h..007h  Secure Area ID (see above)
  008h..00Dh  Fixed (FFh,DEh,FFh,E7h,FFh,DEh)
  00Eh..00Fh  CRC16 across following 7E0h bytes, ie. [010h..7FFh]
  010h..7FDh  Unknown/random values, mixed with some THUMB SWI calls
  7FEh..7FFh  Fixed (00h,00h)
</PRE></TD></TR></TBODY></TABLE>Of which, only the ID in the first 8 bytes is 
verified. Neither BIOS nor (current) firmare versions are verifying the data at 
008h..7FFh, so the 7F8h bytes may be also used for normal program 
code/data.<BR><BR><B>Avoiding Secure Area Encryption</B><BR>WLAN files are 
reportedly same format as cartridges, but without Secure Area, so games with 
Secure Area cannot be booted via WLAN. No$gba can encrypt and decrypt Secure 
Areas only if the NDS BIOS-images are present. And, Nintendo's devkit doesn't 
seem to support Secure Area encryption of unreleased games.<BR>So, unencrypted 
cartridges are more flexible in use. Ways to avoid encryption (which still work 
on real hardware) are:<BR>1) Set NDS9 ROM offset to 4000h, and leave the first 
800h bytes of the Secure Area 00h-filled, which can be (and will be) safely 
destroyed during loading; due to the missing "encryObj" ID; that method is used 
by Nintendo's devkit.<BR>2) Set NDS9 ROM offset to 8000h or higher (cartridge 
has no Secure Area at all).<BR>3) Set NDS9 ROM offset, RAM address, and size to 
zero, set NDS7 ROM offset to 200h, and point both NDS9 and NDS7 entrypoints into 
the loaded NDS7 region. That method avoids waste of unused memory at 
200h..3FFFh, and it should be compatible with the NDS console, however, it is 
not comaptible with commercial cartridges - which do silently redirect address 
below 4000h to 8000h+(addr AND 1FFh). Still, it should work with inofficial 
flashcards, which do not do that redirection. No$gba emulates the redirection 
for regular official cartridges, but it disables redirection for homebrew carts 
if NDS7 rom offset&lt;8000h, and NDS7 size&gt;0.<BR>[One possible problem: Newer 
"anti-passme" firmware versions reportedly check that the entrypoint isn't set 
to 80000C0h, that firmwares might also reject NDS9 entrypoints within the NDS7 
bootcode region?]<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgeicontitle></A><FONT size=+2>&nbsp;DS Cartridge 
      Icon/Title</FONT></TD></TR></TBODY></TABLE><BR>The ROM offset of the Icon/Title 
is defined in Cartridge Header [68h].<BR>If it is present (nonzero), then 
Icon/Title are displayed in the bootmenu.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr  Siz  Expl.
  000h  2    Version  (0001h)
  002h  2    CRC16 across entries 020h..83Fh
  004h  1Ch  Reserved (zero-filled)
  020h  200h Icon Bitmap  (32x32 pix) (4x4 tiles, each 4x8 bytes, 4bit depth)
  220h  20h  Icon Palette (16 colors, 16bit, range 0000h-7FFFh)
             (Color 0 is transparent, so the 1st palette entry is ignored)
  240h  100h Title 0 Japanese (128 characters, 16bit Unicode)
  340h  100h Title 1 English  ("")
  440h  100h Title 2 French   ("")
  540h  100h Title 3 German   ("")
  640h  100h Title 4 Italian  ("")
  740h  100h Title 5 Spanish  ("")
  840h  ?    (Maybe newer/chinese firmware do also support chinese title?)
  840h  -    End of Icon/Title structure (next 1C0h bytes usually FFh-filled)
</PRE></TD></TR></TBODY></TABLE>Usually, for non-multilanguage games, the same 
(english) title is stored in all title entries. The title may consist of ASCII 
characters 0020h-007Fh, character 000Ah (linefeed), and should be 
terminated/padded by 0000h. The whole text should not exceed the dimensions of 
the DS cart field in the bootmenu. The title is usually split into a primary 
title, optional sub-title, and manufacturer, each separated by 000Ah 
character(s). For example, "America",000Ah,"The Axis of 
War",000Ah,"Cynicware",0000h<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgeprotocol></A><FONT size=+2>&nbsp;DS Cartridge 
      Protocol</FONT></TD></TR></TBODY></TABLE><BR>Communication with Cartridge ROM 
relies on sending 8 byte commands to the cartridge, after the sending the 
command, a data stream can be received from the cartridge (the length of the 
data stream isn't fixed, below descriptions show the default length in brackets, 
but one may receive more, or less bytes, if desired).<BR><BR><B>Cartridge Memory 
Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0000h-0FFFh Header (unencrypted)
  1000h-3FFFh Not read-able (zero filled in ROM-images)
  4000h-7FFFh Secure Area, 16KBytes (first 2Kbytes with extra encryption)
  8000h-...   Main Data Area
</PRE></TD></TR></TBODY></TABLE>Cartridge memory must be copied into Work RAM 
(the CPU cannot execute code in ROM).<BR><BR><B>Command Summary, 
Cmd/Reply-Encryption Type, Default Length</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Command/Params    Expl.                             Cmd  Reply Len
  -- Unencrypted Load --
  9F00000000000000h Dummy (read HIGH-Z bytes)         RAW  RAW   2000h
  0000000000000000h Get Cartridge Header              RAW  RAW   200h
  9000000000000000h 1st Get ROM Chip ID               RAW  RAW   4
  00aaaaaaaa000000h Unencrypted Data (debug ver only) RAW  RAW   200h
  3Ciiijjjxkkkkkxxh Activate KEY1 Encryption Mode     RAW  RAW   0
  -- Secure Area Load --
  4llllmmmnnnkkkkkh Activate KEY2 Encryption Mode     KEY1 FIX   910h+0
  1lllliiijjjkkkkkh 2nd Get ROM Chip ID               KEY1 KEY2  910h+4
  xxxxxxxxxxxxxxxxh Invalid - Get KEY2 Stream XOR 00h KEY1 KEY2  910h+...
  2bbbbiiijjjkkkkkh Get Secure Area Block (4Kbytes)   KEY1 KEY2  910h+11A8h
  6lllliiijjjkkkkkh Optional KEY2 Disable             KEY1 KEY2  910h+?
  Alllliiijjjkkkkkh Enter Main Data Mode              KEY1 KEY2  910h+0
  -- Main Data Load --
  B7aaaaaaaa000000h Encrypted Data Read               KEY2 KEY2  200h
  B800000000000000h 3rd Get ROM Chip ID               KEY2 KEY2  4
  xxxxxxxxxxxxxxxxh Invalid - Get KEY2 Stream XOR 00h KEY2 KEY2  ...
</PRE></TD></TR></TBODY></TABLE>The parameter digits contained in above commands 
are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  aaaaaaaa     32bit ROM address (command B7 can access only 8000h and up)
  bbbb         Secure Area Block number (0004h..0007h for addr 4000h..7000h)
  x,xx         Random, not used in further commands
  iii,jjj,llll Random, must be SAME value in further commands
  kkkkk        Random, must be INCREMENTED after FURTHER commands
  mmm,nnn      Random, used as KEY2-encryption seed
</PRE></TD></TR></TBODY></TABLE><BR>++++ Unencrypted Commands (First Part of 
Boot Procedure) ++++<BR><BR><B>Cartridge Reset</B><BR>The /RES Pin switches the 
cartridge into unencrypted mode. After reset, the first two commands (9Fh and 
00h) are transferred at 4MB/s CLK rate.<BR><BR><B>9F00000000000000h (2000h) - 
Dummy</B><BR>Dummy command send after reset, returns endless stream of HIGH-Z 
bytes (ie. usually receiving FFh, immediately after sending the command, the 
first 1-2 received bytes may be equal to the last command 
byte).<BR><BR><B>0000000000000000h (200h) - Get Header</B><BR>Returns RAW 
unencrypted cartridge header, repeated every 1000h bytes. The interesting area 
are the 1st 200h bytes, the rest is typically zero filled.<BR>The Gamecode 
header entry is used later on to initialize the encryption. Also, the ROM 
Control entries define the length of the KEY1 dummy periods (typically 910h 
clocks), and the CLK transfer rate for further commands (typically faster than 
the initial 4MB/s after power up).<BR><BR><B>9000000000000000h (4) - 1st Get ROM 
Chip ID</B><BR>Returns RAW unencrypted Chip ID (eg. C2h,0Fh,00h,00h), repeated 
every 4 bytes.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1st byte - Manufacturer (C2h = Macronix)
  2nd byte - Chip size in megabytes minus 1 (eg. 0Fh = 16MB)
  3rd byte - Reserved/zero (probably upper bits of chip size)
  4th byte - Bit7: Secure Area Block transfer mode (8x200h or 1000h)
</PRE></TD></TR></TBODY></TABLE>Existing/known NDS chip sizes are 16MB (eg. 
Metroid Demo), 32MB (eg. Over the Hedge), and 64MB (eg. Ultimate 
Spiderman).<BR><BR><B>3Ciiijjjxkkkkkxxh (0) - Activate KEY1 Encryption 
Mode</B><BR>The 3Ch command returns endless stream of HIGH-Z bytes, all 
following commands, and their return values, are encrypted. The random 
parameters iii,jjj,kkkkk must be re-used in further commands; the 20bit kkkkk 
value is to be incremented by one after each &lt;further&gt; command (it is 
&lt;not&gt; incremented after the 3Ch command).<BR><BR>++++ KEY1 Encrypted 
Commands (2nd Part of Boot procedure) ++++<BR><BR><B>4llllmmmnnnkkkkkh (910h) - 
Activate KEY2 Encryption Mode</B><BR>KEY1 encrypted command, parameter mmmnnn is 
used to initialize the KEY2 encryption stream. Returns 910h dummy bytes (which 
are still subject to old KEY2 settings; at pre-initialization time, this is 
fixed: HIGH-Z, C5h, 3Ah, 81h, etc.). The new KEY2 seeds are then applied, and 
the first KEY2 byte is then precomputed. The 910h dummy stream is followed by 
that precomputed byte value endless repeated (this is the same value as that 
"underneath" of the first HIGH-Z dummy-byte of the next 
command).<BR><BR><B>1lllliiijjjkkkkkh (914h) - 2nd Get ROM Chip ID / Get KEY2 
Stream</B><BR>KEY1 encrypted command. Returns 910h dummy bytes, followed by KEY2 
encrypted Chip ID repeated every 4 bytes, which must be identical as for the 1st 
Get ID command. The BIOS randomly executes this command once or twice. Changing 
the first command byte to any other value returns an endless KEY2 encrypted 
stream of 00h bytes, that is the easiest way to retrieve encryption values and 
to bypass the copyprotection.<BR><BR><B>2bbbbiiijjjkkkkkh (19B8h) - Get Secure 
Area Block</B><BR>KEY1 encrypted command. Used to read a secure area block (bbbb 
in range 0004h..0007h for addr 4000h..7000h), each block is 4K, so it requires 
four Get Secure Area commands to receive the whole Secure Area (ROM locations 
4000h-7FFFh), the BIOS is reading these blocks in random order.<BR>Normally (if 
the upper bit of the Chip ID is set): Returns 910h dummy bytes, followed by 200h 
KEY2 encrypted Secure Area bytes, followed by 18h KEY2 encrypted 00h bytes, then 
the next 200h KEY2 encrypted Secure Area bytes, again followed by 18h KEY2 
encrypted 00h bytes, and so on. That stream is repeated every 10C0h bytes 
(8x200h data bytes, plus 8x18h zero bytes).<BR>Alternately (if the upper bit of 
the Chip ID is zero): Returns 910h dummy bytes, followed by 1000h KEY2 encrypted 
Secure Area bytes, presumably followed by 18h bytes, too.<BR>Aside from above 
KEY2 encryption (which is done by hardware), the first 2K of the Secure Area is 
additionally KEY1 encrypted (which must be resolved after transfer by 
software).<BR><BR><B>6lllliiijjjkkkkkh (0) - Optional KEY2 Disable</B><BR>KEY1 
encrypted command. Returns 910h dummy bytes (which are still KEY2 affected), 
followed by endless stream of RAW 00h bytes. KEY2 encryption is disabled for all 
following commands.<BR>This command is send only if firmware[18h] matches 
encrypted string "enPngOFF", and ONLY if firmware get_crypt_keys had completed 
BEFORE completion of secure area loading, this timing issue may cause unstable 
results.<BR><BR><B>Alllliiijjjkkkkkh (910h) - Enter Main Data Mode</B><BR>KEY1 
encrypted command. Returns 910h dummy bytes, followed by endless KEY2 encrypted 
stream of 00h bytes. All following commands are KEY2 encrypted.<BR><BR>++++ KEY2 
Encrypted Commands (Main Data Transfer) ++++<BR><BR><B>B7aaaaaaaa000000h (200h) 
- Get Data</B><BR>KEY2 encrypted command. The desired ROM address is specifed, 
MSB first, in parameter bytes (a). Can be used only for addresses 8000h and up, 
smaller addresses will be silently redirected to address "8000h+(addr AND 
1FFh)". There is no alignment restriction for the address. However, the 
datastream wraps to the begin of the current 4K block when address+length 
crosses a 4K boundary (1000h bytes). Returned data is KEY2 
encrypted.<BR><BR><B>B800000000000000h (4) - 3rd Get ROM Chip ID</B><BR>KEY2 
encrypted command. Returns KEY2 encrypted Chip ID repeated every 4 
bytes.<BR><BR><B>xxxxxxxxxxxxxxxxh - Invalid Command</B><BR>Any other command 
(anything else than above B7h and B8h) in KEY2 command mode causes communcation 
failures. The invalid command returns an endless KEY2 encrypted stream of 00h 
bytes. After the invalid command, the KEY2 stream is NOT advanced for further 
command bytes, further commands seems to return KEY2 encrypted 00h bytes, of 
which, the first returned byte appears to be HIGH-Z.<BR>Ie. the cartridge seems 
to have switched back to a state similar to the KEY1-phase, although it doesn't 
seem to be possible to send KEY1 commands.<BR><BR>++++ Notes ++++<BR><BR><B>KEY1 
Command Encryption / 910h Dummy Bytes</B><BR>All KEY1 encrypted commands are 
followed by 910h dummy byte transfers, these 910h clock cycles are probably used 
to decrypt the command at the cartridge side; communication will fail when 
transferring less than 910h bytes.<BR>The return values for the dummy transfer 
are: A single HIGH-Z byte, followed by 90Fh KEY2-encrypted 00h bytes. The KEY2 
encryption stream is advanced for all 910h bytes, including for the HIGH-Z 
byte.<BR>Note: Current cartridges are using 910h bytes, however, other carts 
might use other amounts of dummy bytes, the 910h value can be calculated based 
on ROM Control entries in cartridge header. For the KEY1 formulas, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsencryptionbygamecodeidcodekey1">DS 
Encryption by Gamecode/Idcode (KEY1)</A><BR><BR><B>KEY2 Command/Data 
Encryption</B><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsencryptionbyrandomseedkey2">DS 
Encryption by Random Seed (KEY2)</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgebackup></A><FONT size=+2>&nbsp;DS Cartridge 
      Backup</FONT></TD></TR></TBODY></TABLE><BR><B>SPI Bus Backup Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Type   Total Size  Page Size  Chip/Example      Game/Example
  EEPROM 0.5K bytes   16 bytes  ST M95040-W       (eg. Metroid Demo)
  EEPROM   8K bytes   32 bytes  ST M95640-W       (eg. Super Mario DS)
  EEPROM  64K bytes  128 bytes  ST M95512-W       (eg. Downhill Jam)
  FLASH  256K bytes  256 bytes  ST M45PE20        (eg. Skateland)
  FLASH  512K bytes  256 bytes  ST M25PE40?       (eg. which/any games?)
  FRAM     8K bytes   No limit  ?                 (eg. which/any games?)
  FRAM    32K bytes   No limit  Ramtron FM25L256? (eg. which/any games?)
</PRE></TD></TR></TBODY></TABLE><BR><B>Lifetime Stats</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Type      Max Writes per Page    Data Retention
  EEPROM    100,000                40 years
  FLASH     100,000                20 years
  FRAM      No limit               10 years
</PRE></TD></TR></TBODY></TABLE><BR>SPI Bus Backup Memory is accessed via Ports 
40001A0h and 40001A2h, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeioports">DS Cartridge I/O 
Ports</A><BR><BR><B>Commands</B><BR>For all EEPROM and FRAM types:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06h WREN  Write Enable                Cmd, no parameters
  04h WRDI  Write Disable               Cmd, no parameters
  05h RDSR  Read Status Register        Cmd, read repeated status value(s)
  01h WRSR  Write Status Register       Cmd, write one-byte value
  9Fh RDID  Read JEDEC ID (not supported on EEPROM/FLASH, returns FFh-bytes)
</PRE></TD></TR></TBODY></TABLE>For 0.5K EEPROM (8+1bit Address):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  03h RDLO  Read from Memory 000h-0FFh  Cmd, addr lsb, read byte(s)
  0Bh RDHI  Read from Memory 100h-1FFh  Cmd, addr lsb, read byte(s)
  02h WRLO  Write to Memory 000h-0FFh   Cmd, addr lsb, write 1..MAX byte(s)
  0Ah WRHI  Write to Memory 100h-1FFh   Cmd, addr lsb, write 1..MAX byte(s)
</PRE></TD></TR></TBODY></TABLE>For 8K..64K EEPROM and for FRAM (16bit 
Address):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  03h RD    Read from Memory            Cmd, addr msb,lsb, read byte(s)
  02h WR    Write to Memory             Cmd, addr msb,lsb, write 1..MAX byte(s)
</PRE></TD></TR></TBODY></TABLE>Note: MAX = Page Size (see above chip list) (no 
limit for FRAM).<BR><BR>For FLASH backup, commands should be same as for 
Firmware FLASH memory:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsfirmwareserialflashmemory">DS 
Firmware Serial Flash Memory</A><BR><BR><B>Status Register</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0   WIP  Write in Progress (1=Busy) (Read only) (always 0 for FRAM chips)
  1   WEL  Write Enable Latch (1=Enable) (Read only, except by WREN,WRDI)
  2-3 WP   Write Protect (0=None, 1=Upper quarter, 2=Upper Half, 3=All memory)
</PRE></TD></TR></TBODY></TABLE>For 0.5K EEPROM:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4-7 ONEs Not used (all four bits are always set to "1" each)
</PRE></TD></TR></TBODY></TABLE>For 8K..64K EEPROM and for FRAM:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4-6 ZERO Not used (all three bits are always set to "0" each)
  7   SRWD Status Register Write Disable (0=Normal, 1=Lock) (Only if /W=LOW)
</PRE></TD></TR></TBODY></TABLE>WEL gets reset on Power-up, WRDI, WRSR, 
WRITE/LO/HI, and on /W=LOW.<BR>The WRSR command allows to change ONLY the two WP 
bits, and the SRWD bit (if any), these bits are non-volatile (remain intact 
during power-down), respectively, the WIP bit must be checked to sense WRSR 
completion.<BR><BR><B>Detection (by examining hardware responses)</B><BR>The 
overall memory type and bus-width can be detected by RDSR/RDID commands:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RDSR  RDID          Type         (bus-width)
  FFh,  FFh,FFh,FFh   None         (none)
  F0h,  FFh,FFh,FFh   EEPROM       (with 8+1bit address bus)
  00h,  FFh,FFh,FFh   EEPROM/FRAM  (with 16bit address bus)
  00h,  xxh,xxh,xxh   FLASH        (usually with 24bit address bus)
</PRE></TD></TR></TBODY></TABLE>And, the RD commands can be used to detect the 
memory size/mirrors (though that won't work if the memory is 
empty).<BR><BR><B>Pin-Outs for EEPROM and FRAM chips</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Pin Name Expl.
  1  /S    Chip Select
  2  Q     Data Out
  3  /W    Write-Protect (not used in NDS, wired to VCC)
  4  VSS   Ground
  5  D     Data In
  6  C     Clock
  7  /HOLD Transfer-pause (not used in NDS, wired to VCC)
  8  VCC   Supply 2.5 to 5.5V for M95xx0-W
</PRE></TD></TR></TBODY></TABLE><BR>FRAM (Ferroelectric Nonvolatile RAM) is 
fully backwards compatible with normal EEPROMs, but comes up with faster 
write/erase time (no delays), and with lower power consumption, and unlimited 
number of write/erase cycles. Unlike as for normal RAM, as far as I understand, 
the data remains intact without needing any battery.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgeioports></A><FONT size=+2>&nbsp;DS Cartridge I/O 
      Ports</FONT></TD></TR></TBODY></TABLE><BR>The Gamecard bus registers can be 
mapped to NDS7 or NDS9 via EXMEMCNT, see<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrol">DS Memory 
Control</A><BR><BR><B>40001A0h - NDS7/NDS9 - AUXSPICNT - Gamecard ROM and SPI 
Control</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   SPI Baudrate        (0=4MHz/Default, 1=2MHz, 2=1MHz, 3=512KHz)
  2-5   Not used            (always zero)
  6     SPI Hold Chipselect (0=Deselect after transfer, 1=Keep selected)
  7     SPI Busy            (0=Ready, 1=Busy) (presumably Read-only)
  8-12  Not used            (always zero)
  13    NDS Slot Mode       (0=Parallel/ROM, 1=Serial/SPI-Backup)
  14    Transfer Ready IRQ  (0=Disable, 1=Enable) (for ROM, not for AUXSPI)
  15    NDS Slot Enable     (0=Disable, 1=Enable) (for both ROM and AUXSPI)
</PRE></TD></TR></TBODY></TABLE>The "Hold" flag should be cleared BEFORE 
transferring the LAST data unit, the chipselect will be then automatically 
cleared after the transfer, the program should issue a WaitByLoop(12) (on NDS7, 
or longer on NDS9) manually AFTER the LAST transfer.<BR><BR><B>40001A2h - 
NDS7/NDS9 - AUXSPIDATA - Gamecard SPI Bus Data/Strobe (R/W)</B><BR>The SPI 
transfer is started on writing to this register, so one must &lt;write&gt; a 
dummy value (should be zero) even when intending to &lt;read&gt; from SPI 
bus.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7  Data
  8-15 Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>During transfer, the Busy flag in AUXSPICNT is 
set, and the written DATA value is transferred to the device (via output line), 
simultaneously data is received (via input line). Upon transfer completion, the 
Busy flag goes off, and the received value can be then read from AUXSPIDATA, if 
desired.<BR><BR><B>40001A4h - NDS7/NDS9 - ROMCTRL - Gamecard Bus ROMCTRL 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Expl.
  0-12  KEY1 length part1 (0-1FFFh) (forced min 08F8h by BIOS)
  13    KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)
  14     "SE" Unknown? (usually same as Bit13)
  15    KEY2 Apply Seed   (0=No change, 1=Apply Encryption Seed) (Write only)
  16-21 KEY1 length part2 (0-3Fh)   (forced min 18h by BIOS)
  22    KEY2 encrypt cmd  (0=Disable, 1=Enable KEY2 Encryption for Commands)
  23    Data-Word Status  (0=Busy, 1=Ready/DRQ) (Read-only)
  24-26 Data Block size   (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)
  27    Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)
  28    Secure Area Mode  (0=Normal, 1=Other)
  29     "RESB" Unknown (always 1 ?) (not read/write-able)
  30     "WR"   Unknown (always 0 ?) (read/write-able)
  31    Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)
</PRE></TD></TR></TBODY></TABLE>The cartridge header is booted at 4.2MHz CLK 
rate, and following transfers are then using ROMCTRL settings specified in 
cartridge header entries [060h] and [064h], which are usually using 6.7MHz CLK 
rate. When using other CLK rate, the Timeout in header [06Eh] must be probably 
adjusted accordingly.<BR>Transfer length of null, four, and 200h..4000h bytes 
are supported by the console, however, regular cartridges support only max 1000h 
bytes.<BR><BR><B>40001A8h - NDS7/NDS9 - Gamecard bus 8-byte Command 
Out</B><BR>The separate commands are described in the Cartridge Protocol 
chapter, however, once when the BIOS boot procedure has completed, one would 
usually only need command "B7aaaaaaaa000000h", for reading data (usually 200h 
bytes) from address aaaaaaaah (which should be usually aligned by 200h).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   1st Command Byte (at 40001A8h) (eg. B7h) (MSB)
  8-15  2nd Command Byte (at 40001A9h) (eg. addr bit 24-31)
  16-23 3rd Command Byte (at 40001AAh) (eg. addr bit 16-23)
  24-31 4th Command Byte (at 40001ABh) (eg. addr bit 8-15) (when aligned=even)
  32-39 5th Command Byte (at 40001ACh) (eg. addr bit 0-7)  (when aligned=00h)
  40-47 6th Command Byte (at 40001ADh) (eg. 00h)
  48-57 7th Command Byte (at 40001AEh) (eg. 00h)
  56-63 8th Command Byte (at 40001AFh) (eg. 00h) (LSB)
</PRE></TD></TR></TBODY></TABLE>Observe that the command/parameter MSB is 
located at the smallest memory location (40001A8h), ie. compared with the CPU, 
the byte-order is reversed.<BR><BR><B>4100010h - NDS7/NDS9 - Gamecard bus 4-byte 
Data In (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   1st received Data Byte (at 4100010h)
  8-15  2nd received Data Byte (at 4100011h)
  16-23 3rd received Data Byte (at 4100012h)
  24-31 4th received Data Byte (at 4100013h)
</PRE></TD></TR></TBODY></TABLE>After sending a command, data can be read from 
this register manually (when the DRQ bit is set), or by DMA (with 
DMASAD=4100010h, Fixed Source Address, Length=1, Size=32bit, Repeat=On, Mode=DS 
Gamecard).<BR><BR><B>40001B0h - 32bit - NDS7/NDS9 - Encryption Seed 0 Lower 
32bit (W)</B><BR><B>40001B4h - 32bit - NDS7/NDS9 - Encryption Seed 1 Lower 32bit 
(W)</B><BR><B>40001B8h - 16bit - NDS7/NDS9 - Encryption Seed 0 Upper 7bit 
(bit8-15 unused)</B><BR><B>40001BAh - 16bit - NDS7/NDS9 - Encryption Seed 1 
Upper 7bit (bit8-15 unused)</B><BR>These registers are used by the NDS7 BIOS to 
initialize KEY2 encryption (and there's normally no need to change that initial 
settings). Writes to the Seed registers do not have direct effect on the 
internal encryption registers, until the Seed gets applied by writing "1" to 
ROMCTRL.Bit15.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> For more info:
<A href="http://nocash.emubase.de/gbatek.htm#dsencryptionbyrandomseedkey2">DS Encryption by Random Seed (KEY2)</A><BR>
</PRE></TD></TR></TBODY></TABLE>Note: There are &lt;separate&gt; Seed registers 
for both NDS7 and NDS9, which can be applied by ROMCTRL on NDS7 and NDS9 
respectively (however, once when applied to the internal registers, the new 
internal setting is used for &lt;both&gt; CPUs).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgenitroromfilesystem></A><FONT size=+2>&nbsp;DS 
      Cartridge NitroROM File 
System</FONT></TD></TR></TBODY></TABLE><BR><B>NitroROM</B><BR>The NitroROM 
Filesystem is used by many commercial games, at least those that have been 
developed with Nintendo's tools. The filesystem allows to load data from 
cartridge ROM by filenames and/or by Overlay IDs.<BR>However, the DS hardware, 
BIOS, and Firmware do NOT contain any built-in filesystem functions. The 
ARM9/ARM7 boot code (together max 3903KB), and Icon/Title information are 
automatically loaded on power-up.<BR>Programs that require to load additional 
data from cartridge ROM may do that either by implementing whatever functions to 
translate filenames to ROM addresses, or by reading from ROM 
directly.<BR><BR><B>File Allocation Table (FAT) (base/size defined in cart 
header)</B><BR>Contains ROM addresses for up to 61440 files (File IDs 0000h and 
up).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  00h  4    Start address of file in ROM (8000h and up)    (0=Unused Entry)
  04h  4    End address of file in ROM   (Start+Len...-1?) (0=Unused Entry)
</PRE></TD></TR></TBODY></TABLE>Directories are fully defined in FNT area, and 
do not require FAT entries.<BR><BR><B>File Name Table (FNT) (base/size defined 
in cart header)</B><BR>Consists of the FNT Directory Table, followed by one or 
more FNT Sub-Tables.<BR>To interprete the directory tree: Start at the 1st 
Main-Table entry, which is referencing to a Sub-Table, any directories in the 
Sub-Table are referencing to Main-Table entries, which are referencing to 
further Sub-Tables, and so on.<BR><BR><B>FNT Directory Main-Table (base=FNT+0, 
size=[FNT+06h]*8)</B><BR>Consists of a list of up to 4096 directories (Directory 
IDs F000h and up).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  00h  4    Offset to Sub-table             (originated at FNT base)
  04h  2    ID of first file in Sub-table   (0000h..EFFFh)
</PRE></TD></TR></TBODY></TABLE>For first entry (ID F000h, root directory):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06h  2    Total Number of directories     (1..4096)
</PRE></TD></TR></TBODY></TABLE>Further entries (ID F001h..FFFFh, 
sub-directories):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06h  2    ID of parent directory (F000h..FFFEh)
</PRE></TD></TR></TBODY></TABLE><BR><B>FNT Sub-tables (base=FNT+offset, ends at 
Type/Length=00h)</B><BR>Contains ASCII names for all files and sub-directories 
within a directory.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  00h  1    Type/Length
              01h..7Fh File Entry          (Length=1..127, without ID field)
              81h..FFh Sub-Directory Entry (Length=1..127, plus ID field)
              00h      End of Sub-Table
              80h      Reserved
  01h  LEN  File or Sub-Directory Name, case-sensitive, without any ending
              zero, ASCII 20h..7Eh, except for characters \/?"&lt;&gt;*:;|
</PRE></TD></TR></TBODY></TABLE>Below for Sub-Directory Entries only:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  LEN+1 2    Sub-Directory ID (F001h..FFFFh) ;see FNT+(ID AND FFFh)*8
</PRE></TD></TR></TBODY></TABLE>File Entries do not have above ID field. 
Instead, File IDs are assigned in incrementing order (starting at the "First ID" 
value specified in the Directory Table).<BR><BR><B>ARM9 and ARM7 Overlay Tables 
(OVT) (base/size defined in cart header)</B><BR>Somehow related to Nintendo's 
compiler, allows to assign compiler Overlay IDs to filesystem File IDs, and to 
define additional information such like load addresses.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  00h  4    Overlay ID
  04h  4    RAM Address ;Point at which to load
  08h  4    RAM Size    ;Amount to load
  0Ch  4    BSS Size    ;Size of BSS data region
  10h  4    Static initialiser start address
  14h  4    Static initialiser end address
  18h  4    File ID  (0000h..EFFFh)
  1Ch  4    Reserved (zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>Cartridge Header</B><BR>The base/size of 
FAT, FNT, OVT areas is defined in cartridge header,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgeheader">DS Cartridge 
Header</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgepassmepassthrough></A><FONT size=+2>&nbsp;DS 
      Cartridge PassMe/PassThrough</FONT></TD></TR></TBODY></TABLE><BR>PassMe is an 
adapter connected between the DS and an original NDS cartridge, used to boot 
unencrypted code from a flash cartridge in the GBA slot, it replaces the 
following entries in the original NDS cartridge header:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr  Siz Patch
  004h  4   E59FF018h  ;opcode LDR PC,[027FFE24h] at 27FFE04h
  01Fh  1   04h        ;set autostart bit
  022h  1   01h        ;set ARM9 rom offset to nn01nnnnh (above secure area)
  024h  4   027FFE04h  ;patch ARM9 entry address to endless loop
  034h  4   080000C0h  ;patch ARM7 entry address in GBA slot
  15Eh  2   nnnnh      ;adjust header crc16
</PRE></TD></TR></TBODY></TABLE>After having verified the encrypted chip IDs 
(from the original cartridge), the console thinks that it has successfully 
loaded a NDS cartridge, and then jumps to the (patched) 
entrypoints.<BR><BR><B>GBA Flashcard Format</B><BR>Although the original PassMe 
requires only the entrypoint, PassMe programs should additionally contain one 
(or both) of the ID values below, allowing firmware patches to identify &amp; 
start PassMe games without real PassMe hardware.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0A0h  GBA-style Title    ("DSBooter")
  0ACh  GBA-style Gamecode ("PASS")
  0C0h  ARM7 Entrypoint    (32bit ARM code)
</PRE></TD></TR></TBODY></TABLE>Of course, that applies only to early homebrew 
programs, newer games should use normal NDS cartridge headers.<BR><BR><B>ARM9 
Entrypoint</B><BR>The GBA-slot access rights in the EXMEMCNT register are 
initially assigned to the ARM7 CPU, so the ARM9 cannot boot from the flashcard, 
instead it is switched into an endless loop in Main RAM (which contains a copy 
of the cartridge header at 27FFE00h and up). The ARM7 must thus copy ARM9 code 
to Main RAM, and the set the ARM9 entry address by writing to 
[027FFE24h].<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartridgegbaslot></A><FONT size=+2>&nbsp;DS Cartridge GBA 
      Slot</FONT></TD></TR></TBODY></TABLE><BR>Aside from the 17-pin NDS slot, the DS 
also includes a 32-pin GBA slot. Which is used for backwards compatibility GBA 
mode. Additionally, in DS mode, it can be as expansion port, or for importing 
data from GBA games.<BR>In DS mode, ROM, SRAM, FLASH backup, and whatever 
peripherals contained in older GBA cartridges can be accessed (almost) 
identically as in GBA mode,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartridges">GBA 
Cartridges</A><BR><BR><B>Addressing</B><BR>In DS mode, only one ROM-region is 
present at 8000000h-9FFFFFFh (ie. without the GBA's mirrored WS1 and WS2 regions 
at A000000h-DFFFFFFh). The expansion region (for SRAM/FLASH/etc) has been moved 
from E000000h-E00FFFFh (GBA-mode) to A000000h-A00FFFFh 
(DS-mode).<BR><BR><B>Timings</B><BR>GBA timings are specified as "waitstates" 
(excluding 1 access cycle), NDS timings are specified as (total) "access time". 
And, the NDS bus-clock is twice as fast as for GBA. So, for "N" GBA waitstates, 
the NDS access time should be "(N+1)*2". Timings are controlled via NDS EXMEMCNT 
instead GBA WAITCNT,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsmemorycontrolcartridgesandmainram">DS 
Memory Control - Cartridges and Main RAM</A><BR><BR><B>GBA EEPROM</B><BR>EEPROMs 
in GBA carts cannot be accessed in DS mode. The EEPROMs should be accessed with 
8 waits on GBA, ie. 18 cycles on NDS on both 1st/2nd access. But, 2nd access is 
restricted to max 6 cycles in NDS mode, which is ways too fast.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartrumblepak></A><FONT size=+2>&nbsp;DS Cart Rumble 
      Pak</FONT></TD></TR></TBODY></TABLE><BR><B>DS Rumble Option Pak</B><BR>The 
Rumble Pak comes bundled with Metroid Prime Pinball. It contains a small 
actuator made by ALPS to make it rumble. The original device (NTR-008) is sized 
like a normal GBA cartridge, and there's also shorter variant for the DS-Lite 
(USG-006).<BR>The rumble pak is pretty simple internally, it only wires up to a 
few pins on the GBA Cartridge Port:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  VCC, GND, /WR, AD1, and IRQ (grounded)
</PRE></TD></TR></TBODY></TABLE>AD1 runs into a little 8 pin chip, which is 
probably just a latch on the rising edge of /WR. A line runs from this chip to a 
transistor that is directly connected to the actuator. The only other chip on 
the board is a 5 pin jobber, probably a power component.<BR>For detection, AD1 
seems to be pulled low when reading from it, the other AD lines are open bus 
(containing the halfword address), so one can do:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to 0FFFh
    if halfword[8000000h+i*2]&lt;&gt;(i and FFFDh) then &lt;not_a_ds_rumble_pak&gt;
  next i
</PRE></TD></TR></TBODY></TABLE>The actuator doesn't have an on/off setting like 
a motor, it rumbles when you switch it between the two settings. Switch 
frequently for a fast rumble, and fairly slowly for more of a 'tick' effect. 
That should be done via timer irq:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  rumble_state = rumble_state xor 0002h
  halfword[8000000h]=rumble_state
</PRE></TD></TR></TBODY></TABLE>Unknown if one of the two states has higher 
power-consumption than the other, ie. if it's a "pull/release" mechanism, if so, 
then disabling rumble should be done by using the "release" state, which would 
be AD1=0, or AD1=1...?<BR>Note: The v3 firmware can detect the Rumble Pak as an 
option pak, but it does not provide an enable/disable rumble option in the alarm 
menu.<BR><BR><B>GBA Rumble Carts</B><BR>There are also a few GBA games that 
contain built-in Rumble, and which could be used by NDS games as well. To be 
user friendly, best support both types.<BR><A 
href="http://nocash.emubase.de/gbatek.htm#gbacartrumble">GBA Cart 
Rumble</A><BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartunknownaddons></A><FONT size=+2>&nbsp;DS Cart Unknown 
      Add-Ons</FONT></TD></TR></TBODY></TABLE><BR><B>DS Memory Expansion Pak (NTR-011 
or USG-007)</B><BR>Connects to the GBA slot. Reportedly used for a NDS browser. 
Might be also used by other bloated programs. Up to now, access times, memory 
region, bus-width, chip types, and even the memory size seem to be totally 
unknown.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartcheatactionreplayds></A><FONT size=+2>&nbsp;DS Cart 
      Cheat Action Replay DS</FONT></TD></TR></TBODY></TABLE><BR>The first commercial 
DS cheat code solution, this device was developed by Datel. It supports swapping 
out cartridges after loading the AR software. For updating, the user may either 
manually enter codes or use the included proprietary USB cable that comes with 
the device. The user has been able to manually update codes since firmware 
version 1.52.<BR><BR><B>Action Replay DS Codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ABCD-NNNNNNNN       Game ID ;ASCII Gamecode [00Ch] and CRC32 across [0..1FFh]
  00000000 XXXXXXXX   manual hook codes (rarely used) (default is auto hook)
  0XXXXXXX YYYYYYYY   word[XXXXXXX+offset] = YYYYYYYY
  1XXXXXXX 0000YYYY   half[XXXXXXX+offset] = YYYY
  2XXXXXXX 000000YY   byte[XXXXXXX+offset] = YY
  3XXXXXXX YYYYYYYY   IF YYYYYYYY &gt; word[XXXXXXX]   ;unsigned    ;\
  4XXXXXXX YYYYYYYY   IF YYYYYYYY &lt; word[XXXXXXX]   ;unsigned    ; for v1.54,
  5XXXXXXX YYYYYYYY   IF YYYYYYYY = word[XXXXXXX]                ; when X=0,
  6XXXXXXX YYYYYYYY   IF YYYYYYYY &lt;&gt; word[XXXXXXX]               ; uses
  7XXXXXXX ZZZZYYYY   IF YYYY &gt; ((not ZZZZ) AND half[XXXXXXX])   ; [offset]
  8XXXXXXX ZZZZYYYY   IF YYYY &lt; ((not ZZZZ) AND half[XXXXXXX])   ; instead of
  9XXXXXXX ZZZZYYYY   IF YYYY = ((not ZZZZ) AND half[XXXXXXX])   ; [XXXXXXX]
  AXXXXXXX ZZZZYYYY   IF YYYY &lt;&gt; ((not ZZZZ) AND half[XXXXXXX])  ;/
  BXXXXXXX 00000000   offset = word[XXXXXXX+offset]
  C0000000 YYYYYYYY   FOR loopcount=0 to YYYYYYYY  ;execute Y+1 times
  C4000000 00000000   offset = address of the C4000000 code           ;v1.54
  C5000000 XXXXYYYY   counter=counter+1, IF (counter AND YYYY) = XXXX ;v1.54
  C6000000 XXXXXXXX   [XXXXXXXX]=offset                               ;v1.54
  D0000000 00000000   ENDIF
  D1000000 00000000   NEXT loopcount
  D2000000 00000000   NEXT loopcount, and then FLUSH everything
  D3000000 XXXXXXXX   offset = XXXXXXXX
  D4000000 XXXXXXXX   datareg = datareg + XXXXXXXX
  D5000000 XXXXXXXX   datareg = XXXXXXXX
  D6000000 XXXXXXXX   word[XXXXXXXX+offset]=datareg, offset=offset+4
  D7000000 XXXXXXXX   half[XXXXXXXX+offset]=datareg, offset=offset+2
  D8000000 XXXXXXXX   byte[XXXXXXXX+offset]=datareg, offset=offset+1
  D9000000 XXXXXXXX   datareg = word[XXXXXXXX+offset]
  DA000000 XXXXXXXX   datareg = half[XXXXXXXX+offset]
  DB000000 XXXXXXXX   datareg = byte[XXXXXXXX+offset] ;bugged on pre-v1.54
  DC000000 XXXXXXXX   offset = offset + XXXXXXXX
  EXXXXXXX YYYYYYYY   Copy YYYYYYYY parameter bytes to [XXXXXXXX+offset...]
  44332211 88776655   parameter bytes 1..8 for above code  (example)
  0000AA99 00000000   parameter bytes 9..10 for above code (padded with 00s)
  FXXXXXXX YYYYYYYY   Copy YYYYYYYY bytes from [offset..] to [XXXXXXX...]
</PRE></TD></TR></TBODY></TABLE>IF/ENDIF can be nested up to 32 times. FOR/NEXT 
cannot be nested, any FOR statement does forcefully terminate any prior loop. 
FOR does backup the current IF condidition flags, and NEXT does restore these 
flags, so ENDIF(s) aren't required inside of the loop. The NEXT+FLUSH command 
does (after finishing the loop) reset offset=0, datareg=0, and does clear all 
condition flags, so further ENDIF(s) aren't required after the loop.<BR>Before 
v1.54, the DB000000 code did accidently set offset=offset+XXXXXXX after 
execution of the code. For all word/halfword accesses, the address should be 
aligned accordingly. For the COPY commands, addresses should be aligned by four 
(all data is copied with ldr/str, except, on odd lengths, the last 1..3 bytes do 
use ldrb/strb).<BR>offset, datareg, loopcount, and counter are internal 
registers in the action replay software.<BR><BR>&gt; The condition register is 
checked, for all code types<BR>&gt; but the D0, D1 and D2 code type<BR>Makes 
sense.<BR><BR>&gt; and for the C5 code type it's checked AFTER the counter 
has<BR>&gt; been incremented (so the counter is always incremented<BR>I love 
that exceptions ;-)<BR><BR><B>Hook</B><BR>The hook codes consist of a series of 
nine 00000000 XXXXXXXX codes, and must be marked as (M) code (for not being 
confused with normal 0XXXXXXX YYYYYYYY codes). For all nine codes, the left 
32bit are actually don't care (but should be zero), the meaning of the right 
32bit varies from 1st to 9th code.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1st: Address used prior to launching game (eg. 23xxxxxh)
  2nd: Address to write the hook at (inside the ARM7 executable)
  3rd: Hook final address (huh?)
  4th: Hook mode selection (0=auto, 1=mode1, 2=mode2)
  5th: Opcode that replaces the hooked one (eg. E51DE004h)
  6th: Address to store important stuff  (default 23FE000h)
  7th: Address to store the code handler (default 23FE074h)
  8th: Address to store the code list    (default 23FE564h)
  9th: Must be 1 (00000001h)
</PRE></TD></TR></TBODY></TABLE>For most games, the AR does automatically hook 
code on the ARM7. Doing that automatically is nice, but hooking ARM7 means that 
there is no access to VRAM, TCM and Cache, which &lt;might&gt; cause problems 
since efficient games &lt;should&gt; store all important data in TCM or Cache 
(though, in practice, I'd doubt that any existing NDS games are that 
efficient).<BR><BR><B>Thanks</B><BR>To Kenobi and Dualscreenman from Kodewerx 
for above ARDS cheat info.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dscartcheatcodebreakerds></A><FONT size=+2>&nbsp;DS Cart Cheat 
      Codebreaker DS</FONT></TD></TR></TBODY></TABLE><BR>This is Pelican's entry into 
the DS cheat-device industry. It supports swapping out the cartridges, and 
alternately, also gives the user the option of connecting another gamecard onto 
it. For updating, the user may either manually enter codes, or use Wifi to 
connect to the Codebreaker update site (that updating will overwrite all 
manually entered codes though).<BR><BR><B>Codebreaker DS Codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ---Initialization---
  0000CR16 GAMECODE                    Specify Game ID, use Encrypted codes
  8000CR16 GAMECODE                    Specify Game ID, use Unencrypted codes
  BEEFC0DE XXXXXXXX                    Change Encryption Keys
  A0XXXXXX YYYYYYYY                    Bootup-Hook 1, X=Address, Y=Value
  A8XXXXXX YYYYYYYY                    Bootup-Hook 2, X=Address, Y=Value
  F0XXXXXX TYYYYYYY         Code-Hook 1 (T=Type,Y=CheatEngineAddr,X=HookAddr)
  F8XXXXXX TPPPPPPP         Code-Hook 2 (T=Type,X=CheatEngineHookAddr,P=Params)
  ---General codes---
  00XXXXXX 000000YY                    [X]=YY
  10XXXXXX 0000YYYY                    [X]=YYYY
  20XXXXXX YYYYYYYY                    [X]=YYYYYYYY
  60XXXXXX 000000YY ZZZZZZZZ 00000000  [[X]+Z]=YY
  60XXXXXX 0000YYYY ZZZZZZZZ 10000000  [[X]+Z]=YYYY
  60XXXXXX YYYYYYYY ZZZZZZZZ 20000000  [[X]+Z]=YYYYYYYY
  30XXXXXX 000000YY                    [X]=[X] + YY
  30XXXXXX 0001YYYY                    [X]=[X] + YYYY
  38XXXXXX YYYYYYYY                    [X]=[X] + YYYYYYYY
  70XXXXXX 000000YY                    [X]=[X] OR  YY
  70XXXXXX 001000YY                    [X]=[X] AND YY
  70XXXXXX 002000YY                    [X]=[X] XOR YY
  70XXXXXX 0001YYYY                    [X]=[X] OR  YYYY
  70XXXXXX 0011YYYY                    [X]=[X] AND YYYY
  70XXXXXX 0021YYYY                    [X]=[X] XOR YYYY
  ---Memory fill/copy---
  40XXXXXX 2NUMSTEP 000000YY 000000ZZ  byte[X+(0..NUM-1)*STEP*1]=Y+(0..NUM-1)*Z
  40XXXXXX 1NUMSTEP 0000YYYY 0000ZZZZ  half[X+(0..NUM-1)*STEP*2]=Y+(0..NUM-1)*Z
  40XXXXXX 0NUMSTEP YYYYYYYY ZZZZZZZZ  word[X+(0..NUM-1)*STEP*4]=Y+(0..NUM-1)*Z
  50XXXXXX YYYYYYYY ZZZZZZZZ 00000000  copy Y bytes from [X] to [Z]
  ---Conditional codes (bugged)---
  60XXXXXX 000000YY ZZZZZZZZ 01c100VV  IF [[X]+Z] .. VV   THEN [[X]+Z]=YY
  60XXXXXX 000000YY ZZZZZZZZ 01c0VVVV  IF [[X]+Z] .. VVVV THEN [[X]+Z]=YY
  60XXXXXX 0000YYYY ZZZZZZZZ 11c100VV  IF [[X]+Z] .. VV   THEN [[X]+Z]=YYYY
  60XXXXXX 0000YYYY ZZZZZZZZ 11c0VVVV  IF [[X]+Z] .. VVVV THEN [[X]+Z]=YYYY
  60XXXXXX YYYYYYYY ZZZZZZZZ 21c100VV  IF [[X]+Z] .. VV   THEN [[X]+Z]=YYYYYYYY
  60XXXXXX YYYYYYYY ZZZZZZZZ 21c0VVVV  IF [[X]+Z] .. VVVV THEN [[X]+Z]=YYYYYYYY
  ---Conditional codes (working)---
  D0XXXXXX NNc100YY                    IF [X] .. YY   THEN exec max(1,NN) lines
  D0XXXXXX NNc0YYYY                    IF [X] .. YYYY THEN exec max(1,NN) lines
</PRE></TD></TR></TBODY></TABLE>The condition digits (c=0..7), have the 
following functions:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0 IF [mem] =  imm THEN ...              4 IF ([mem] AND imm) =  0   THEN ...
  1 IF [mem] &lt;&gt; imm THEN ...              5 IF ([mem] AND imm) &lt;&gt; 0   THEN ...
  2 IF [mem] &lt;  imm THEN ... (unsigned)   6 IF ([mem] AND imm) =  imm THEN ...
  3 IF [mem] &gt;  imm THEN ... (unsigned)   7 IF ([mem] AND imm) &lt;&gt; imm THEN ...
</PRE></TD></TR></TBODY></TABLE>Notes<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  GAMECODE  Cartridge Header[00Ch] (32bit in reversed byte-order)
  CR16      Cartridge Header[15Eh] (16bit in normal byte-order)
  XXXXXX    27bit addr (actually 7 digits, XXXXXXX, overlaps 5bit code number)
</PRE></TD></TR></TBODY></TABLE>The "bugged" conditional codes (60XXXXXX) are 
accidently skipping NN lines when the condition is false, where NN is taken from 
the upper 8bit of the code's last 32bit values (ie. exactly as for the D0XXXXXX 
codes). For byte-writes, that would be NN=01h, which can be eventually dealt 
with, although there may be compatibility problems which future versions that 
might fix that bug. For halfword/word writes, NN would be 11h or 21h, so that 
codes are about totally unusable.<BR><BR><B>Codebreaker DS / Encrypted 
Codes</B><BR>The overall "address value" decryption works like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=4Fh to 00h
    y=77628ECFh
    if i&gt;13h then y=59E5DC8Ah
    if i&gt;27h then y=054A7818h
    if i&gt;3Bh then y=B1BF0855h
    address = (Key0-value) xor address
    value   = value - Key1 - (address ror 1Bh)
    address = (address xor (value + y)) ror 13h
    if (i&gt;13h) then
      if (i&lt;=27h) or (i&gt;3Bh) then x=Key2 xor Key1 xor Key0
      else x=((Key2 xor Key1) and Key0) xor (Key1 and Key2)
      value=value xor (x+y+address)
      x = Secure[((i*4+00h) and FCh)+000h]
      x = Secure[((i*4+34h) and FCh)+100h] xor x
      x = Secure[((i*4+20h) and FCh)+200h] xor x
      x = Secure[((i*4+08h) and FCh)+300h] xor x
      address = address - (x ror 19h)
  next i
</PRE></TD></TR></TBODY></TABLE>Upon startup, the initial key settings are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Secure[0..7FFh] = Copy of the ENCRYPTED 1st 2Kbytes of the game's Secure Area
  Key0 = 0C2EAB3Eh, Key1 = E2AE295Dh, Key2 = E1ACC3FFh, Key3 = 70D3AF46h
  scramble_keys
</PRE></TD></TR></TBODY></TABLE>Upon BEEFC0DE XXXXXXXX, the keys get changed 
like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Key0 = Key0 + (XXXXXXXX ror 1Dh)
  Key1 = Key1 - (XXXXXXXX ror 05h)
  Key2 = Key2 xor (Key3 xor Key0)
  Key3 = Key3 xor (Key2  -  Key1)
  scramble_keys
</PRE></TD></TR></TBODY></TABLE>The above scramble_keys function works like 
so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  for i=0 to FFh
    y = byte(xlat_table[i])
    Secure[i*4+000h] = (Secure[i*4+000h] xor Secure[y*4]) + Secure[y*4+100h]
    Secure[i*4+400h] = (Secure[i*4+400h] xor Secure[y*4]) - Secure[y*4+200h]
  next i
  for i=0 to 63h
    Key0 = Key0 xor (Secure[i*4] + Secure[i*4+190h])
    Key1 = Key1 xor (Secure[i*4] + Secure[i*4+320h])
    Key2 = Key2 xor (Secure[i*4] + Secure[i*4+4B0h])
    Key3 = Key3 xor (Secure[i*4] + Secure[i*4+640h])
  next i
  Key0 = Key0  -  Secure[7D0h]
  Key1 = Key1 xor Secure[7E0h]
  Key2 = Key2  +  Secure[7F0h]
  Key3 = Key3 xor Secure[7D0h] xor Secure[7F0h]
</PRE></TD></TR></TBODY></TABLE>the xlat_table consists of 256 fixed 8bit 
values:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  34h,59h,00h,32h,7Bh,D3h,32h,C9h,9Bh,77h,75h,44h,E0h,73h,46h,06h
  0Bh,88h,B3h,3Eh,ACh,F2h,BAh,FBh,2Bh,56h,FEh,7Ah,90h,F7h,8Dh,BCh
  8Bh,86h,9Ch,89h,00h,19h,CDh,4Ch,54h,30h,01h,93h,30h,01h,FCh,36h
  4Dh,9Fh,FDh,D7h,32h,94h,AEh,BCh,2Bh,61h,DFh,B3h,44h,EAh,8Bh,A3h
  2Bh,53h,33h,54h,42h,27h,21h,DFh,A9h,DDh,C0h,35h,58h,EFh,8Bh,33h
  B4h,D3h,1Bh,C7h,93h,AEh,32h,30h,F1h,CDh,A8h,8Ah,47h,8Ch,70h,0Ch
  17h,4Eh,0Eh,A2h,85h,0Dh,6Eh,37h,4Ch,39h,1Fh,44h,98h,26h,D8h,A1h
  B6h,54h,F3h,AFh,98h,83h,74h,0Eh,13h,6Eh,F4h,F7h,86h,80h,ECh,8Eh
  EEh,4Ah,05h,A1h,F1h,EAh,B4h,D6h,B8h,65h,8Ah,39h,B3h,59h,11h,20h
  B6h,BBh,4Dh,88h,68h,24h,12h,9Bh,59h,38h,06h,FAh,15h,1Dh,40h,F0h
  01h,77h,57h,F5h,5Dh,76h,E5h,F1h,51h,7Dh,B4h,FAh,7Eh,D6h,32h,4Fh
  0Eh,C8h,61h,C1h,EEh,FBh,2Ah,FCh,ABh,EAh,97h,D5h,5Dh,E8h,FAh,2Ch
  06h,CCh,86h,D2h,8Ch,10h,D7h,4Ah,CEh,8Fh,EBh,03h,16h,ADh,84h,98h
  F5h,88h,2Ah,18h,ACh,7Fh,F6h,94h,FBh,3Fh,00h,B6h,32h,A2h,ABh,28h
  64h,5Ch,0Fh,C6h,23h,12h,0Ch,D2h,BAh,4Dh,A3h,F2h,C9h,86h,31h,57h
  0Eh,F8h,ECh,E1h,A0h,9Ah,3Ch,65h,17h,18h,A0h,81h,D0h,DBh,D5h,AEh
</PRE></TD></TR></TBODY></TABLE>all used operations are unsigned 32bit 
integer.<BR><BR><B>Thanks</B><BR>To Kenobi and Dualscreenman from Kodewerx for 
above CBDS cheat info.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsencryptionbygamecodeidcodekey1></A><FONT size=+2>&nbsp;DS 
      Encryption by Gamecode/Idcode (KEY1)</FONT></TD></TR></TBODY></TABLE><BR><B>KEY1 
- Gamecode / Idcode Encryption</B><BR>The KEY1 encryption relies only on the 
gamecode (or firmware idcode), it does not contain any random components. The 
fact that KEY1 encrypted commands appear random is just because the 
&lt;unencrypted&gt; commands contain random values, so the encryption result 
looks random.<BR><BR>KEY1 encryption is used for KEY1 encrypted gamecart 
commands (ie. for loading the secure area). It is also used for resolving the 
extra decryption of the first 2K of the secure area, and for firmware 
decryption, and to decode some encrypted values in gamecart/firmware 
header.<BR><BR>Below are KEY1 encryption formulas. The formulas can be used only 
with a copy of the key table (1048h bytes) from the NDS ARM7 BIOS (address 
0030h..1077h).<BR><BR><B>crypt_64bit_up(ptr) / crypt_64bit_down(ptr)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Y=[ptr+0]
  X=[ptr+4]
  FOR I=0 TO 0Fh (up), or FOR I=11h TO 02h (down)
    Z=[keybuf+I*4] XOR X
    X=[keybuf+048h+((Z SHR 24) AND FFh)*4]
    X=[keybuf+448h+((Z SHR 16) AND FFh)*4] + X
    X=[keybuf+848h+((Z SHR  8) AND FFh)*4] XOR X
    X=[keybuf+C48h+((Z SHR  0) AND FFh)*4] + X
    X=Y XOR X
    Y=Z
  NEXT I
  [ptr+0]=X XOR [keybuf+40h], or [ptr+0]=X XOR [keybuf+4h] (down)
  [ptr+4]=Y XOR [keybuf+44h], or [ptr+4]=Y XOR [keybuf+0h] (down)
</PRE></TD></TR></TBODY></TABLE><BR><B>apply_keycode(modulo)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  crypt_64bit_up(keycode+4)
  crypt_64bit_up(keycode+0)
  [scratch]=0000000000000000h   ;S=0 (64bit)
  FOR I=0 TO 44h STEP 4         ;xor with reversed byte-order (bswap)
    [keybuf+I]=[keybuf+I] XOR bswap_32bit([keycode+(I MOD modulo)])
  NEXT I
  FOR I=0 TO 1040h STEP 8
    crypt_64bit_up(scratch)     ;encrypt S (64bit) by keybuf
    [keybuf+I+0]=[scratch+4]    ;write S to keybuf (first upper 32bit)
    [keybuf+I+4]=[scratch+0]    ;write S to keybuf (then lower 32bit)
  NEXT I
</PRE></TD></TR></TBODY></TABLE><BR><B>init_keycode(idcode,level,modulo)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  copy [arm7bios+0030h..1077h] to [keybuf+0..1047h]
  [keycode+0]=[idcode]
  [keycode+4]=[idcode]/2
  [keycode+8]=[idcode]*2
  IF level&gt;=1 THEN apply_keycode(modulo) ;first apply (always)
  IF level&gt;=2 THEN apply_keycode(modulo) ;second apply (optional)
  [keycode+4]=[keycode+4]*2
  [keycode+8]=[keycode+8]/2
  IF level&gt;=3 THEN apply_keycode(modulo) ;third apply (optional)
</PRE></TD></TR></TBODY></TABLE><BR><B>firmware_decryption</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  init_keycode(firmware_header+08h,1,0Ch) ;idcode (usually "MACP"), level 1
  crypt_64bit_down(firmware_header+18h)   ;rominfo
  init_keycode(firmware_header+08h,2,0Ch) ;idcode (usually "MACP"), level 2
  decrypt ARM9 and ARM7 bootcode by crypt_64bit_down (each 8 bytes)
  decompress ARM9 and ARM7 bootcode by LZ77 function (swi)
  calc CRC16 on decrypted/decompressed ARM9 bootcode followed by ARM7 bootcode
</PRE></TD></TR></TBODY></TABLE>Note: The sizes of the compressed/encrypted 
bootcode areas are unknown (until they are fully decompressed), one way to solve 
that problem is to decrypt the next 8 bytes each time when the decompression 
function requires more data.<BR><BR><B>gamecart_decryption</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  init_keycode(cart_header+0Ch,1,08h)   ;gamecode, level 1, modulo 8
  crypt_64bit_down(cart_header+78h)     ;rominfo (secure area disable)
  init_keycode(cart_header+0Ch,2,08h)   ;gamecode, level 2, modulo 8
  crypt_64bit_up all KEY1 commands (1st command byte in MSB of 64bit value)
  after loading the secure_area, calculate secure_area crc, then
  crypt_64bit_down(secure_area+0)       ;first 8 bytes of secure area
  init_keycode(cart_header+0Ch,3,08h)   ;gamecode, level 3, modulo 8
  crypt_64bit_down(secure_area+0..7F8h) ;each 8 bytes in first 2K of secure
</PRE></TD></TR></TBODY></TABLE>After decryption, the ID field in the first 8 
bytes should be "encryObj", if it matches then first 8 bytes are filled with 
E7FFDEFFh, otherwise the whole 2K are filled by that value.<BR><BR><B>Gamecart 
Command Register</B><BR>Observe that the byte-order of the command register 
[40001A8h] is reversed. The way how the CPU stores 64bit data in memory (and the 
way how the "crypt_64bit_up" function for KEY1-encrypted commands expects data 
in memory) is LSB at [addr+0] and MSB at [addr+7]. This value is to be 
transferred MSB first. However, the DS hardware transfers [40001A8h+0] first, 
and [40001A8h+7] last. So, the byte order must be reversed when copying the 
value from memory to the command register.<BR><BR><B>Note</B><BR>The KEY1 
encryption is based on Bruce Schneier's "Blowfish Encryption 
Algorithm".<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsencryptionbyrandomseedkey2></A><FONT size=+2>&nbsp;DS 
      Encryption by Random Seed (KEY2)</FONT></TD></TR></TBODY></TABLE><BR><B>KEY2 
39bit Seed Values</B><BR>The pre-initialization settings at cartridge-side 
(after reset) are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Seed0 = 58C56DE0E8h
  Seed1 = 5C879B9B05h
</PRE></TD></TR></TBODY></TABLE>The post-initialization settings (after sending 
command 4llllmmmnnnkkkkkh to the cartridge, and after writing the Seed values to 
Port 40001Bxh) are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Seed0 = (mmmnnn SHL 15)+6000h+Seedbyte
  Seed1 = 5C879B9B05h
</PRE></TD></TR></TBODY></TABLE>The seedbyte is selected by Cartridge Header 
[013h].Bit0-2, this index value should be usually in range 0..5, however, 
possible values for index 0..7 are: E8h,4Dh,5Ah,B1h,17h,8Fh,99h,D5h.<BR>The 
24bit random value (mmmnnn) is derived from the real time clock setting, and 
also scattered by KEY1 encryption, anyways, it's just random and doesn't really 
matter where it comes from.<BR><BR><B>KEY2 Encryption</B><BR>Relies on two 39bit 
registers (x and y), which are initialized as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  x = reversed_bit_order(seed0)  ;ie. LSB(bit0) exchanged with MSB(bit38), etc.
  y = reversed_bit_order(seed1)
</PRE></TD></TR></TBODY></TABLE>During transfer, x, y, and transferred data are 
modified as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  x = (((x shr 5)xor(x shr 17)xor(x shr 18)xor(x shr 31)) and 0FFh)+(x shl 8)
  y = (((y shr 5)xor(y shr 23)xor(y shr 18)xor(y shr 31)) and 0FFh)+(y shl 8)
  data = (data xor x xor y) and 0FFh
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsfirmwareserialflashmemory></A><FONT size=+2>&nbsp;DS 
      Firmware Serial Flash Memory</FONT></TD></TR></TBODY></TABLE><BR><B>ST 
Microelectronics SPI Bus Compatible Serial FLASH Memory</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ST M45PE20 - ID 20h,40h,12h - 256 KBytes (Nintendo DS) (in my old DS)
  ST M35PE20 - ID 20h,50h,12h - 256 KBytes (Nintendo DS) (in my DS-Lite)
  ST M25PE40 - ID 20h,80h,13h - 512 KBytes (iQue DS, with chinese charset)
</PRE></TD></TR></TBODY></TABLE>More than 100,000 Write Cycles, more than 20 
Year Data Retention<BR>The Firmware Flash Memory is accessed via SPI bus,<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dsserialperipheralinterfacebusspi">DS 
Serial Peripheral Interface Bus (SPI)</A><BR><BR><B>Instruction Codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  06h  WREN Write Enable (No Parameters)
  04h  WRDI Write Disable (No Parameters)
  9Fh  RDID Read JEDEC Identification (Read 1..3 ID Bytes)
             (Manufacturer, Device Type, Capacity)
  05h  RDSR Read Status Register (Read Status Register, endless repeated)
             Bit7-2  Not used (zero)
             Bit1    WEL Write Enable Latch             (0=No, 1=Enable)
             Bit0    WIP Write/Program/Erase in Progess (0=No, 1=Busy)
  03h  READ Read Data Bytes (Write 3-Byte-Address, read endless data stream)
  0Bh  FAST Read Data Bytes at Higher Speed (Write 3-Byte-Address, write 1
             dummy-byte, read endless data stream) (max 25Mbit/s)
  0Ah  PW   Page Write (Write 3-Byte-Address, write 1..256 data bytes)
             (changing bits to 0 or 1) (reads unchanged data, erases the page,
             then writes new &amp; unchanged data) (11ms typ, 25ms max)
  02h  PP   Page Program (Write 3-Byte-Address, write 1..256 data bytes)
             (changing bits from 1 to 0) (1.2ms typ, 5ms max)
  DBh  PE   Page Erase 100h bytes (Write 3-Byte-Address) (10ms typ, 20ms max)
  D8h  SE   Sector Erase 10000h bytes (Write 3-Byte-Address) (1s typ, 5s max)
  B9h  DP   Deep Power-down (No Parameters) (consumption 1uA typ, 10uA max)
             (3us) (ignores all further instructions, except RDP)
  ABh  RDP  Release from Deep Power-down (No Parameters) (30us)
</PRE></TD></TR></TBODY></TABLE>Write/Program may not cross page-boundaries. 
Write/Program/Erase are rejected during first 1..10ms after power up. The WEL 
bit is automatically cleared on Power-Up, on /Reset, and on completion of 
WRDI/PW/PP/PE/SE instructions. WEL is set by WREN instruction (which must be 
issued before any write/program/erase instructions). Don't know how RDSR behaves 
when trying to write to the write-protected region?<BR><BR><B>Communication 
Protocol</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Set Chip Select LOW to invoke the command
  Transmit the instruction byte
  Transmit any parameter bytes
  Transmit/receive any data bytes
  Set Chip Select HIGH to finish the command
</PRE></TD></TR></TBODY></TABLE>All bytes (and 3-byte addresses) transferred 
most significant bit/byte first.<BR><BR><B>Pin-Outs</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1   D    Serial Data In (latched at rising clock edge)          _________
  2   C    Serial Clock (max 25MHz)                             /|o        |
  3   /RES Reset                                            1 -| |         |- 8
  4   /S   Chip Select (instructions start at falling edge) 2 -| |         |- 7
  5   /W   Write Protect (makes first 256 pages read-only)  3 -| |_________|- 6
  6   VCC  Supply (2.7V..3.6V typ) (4V max) (DS:VDD3.3)     4 -|/          |- 5
  7   VSS  Ground                                              |___________|
  8   Q    Serial Data Out (changes at falling clock edge)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsfirmwareheader></A><FONT size=+2>&nbsp;DS Firmware 
      Header</FONT></TD></TR></TBODY></TABLE><BR><B>Firmware Memory Map</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00000h-00029h  Firmware Header
  0002Ah-001FFh  Wifi Settings
  00200h-3FDFFh  Firmware Code/Data
  3FE00h-3FEFFh  User Settings Area 1
  3FF00h-3FFFFh  User Settings Area 2
</PRE></TD></TR></TBODY></TABLE>On iQue DS (with 512K flash memory), user 
settings are moved to 7FE00h and up, and, there seems to be some unknown stuff 
at 200h..27Fh.<BR><BR><B>Firmware Header (00000h-001FFh)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  000h 2    part3 romaddr/8 (arm9 gui code) (LZ/huffman compression)
  002h 2    part4 romaddr/8 (arm7 gui code) (LZ/huffman compression)
  004h 2    part3/4 CRC16 arm9/7 gui code
  006h 2    part1/2 CRC16 arm9/7 boot code
  008h 4    firmware identifier (usually nintendo "MAC",nn) (or nocash "XBOO")
            the 4th byte (nn) occassionally changes in different version
  00Ch 2    part1 arm9 boot code romaddr/2^(2+shift1) (LZSS compressed)
  00Eh 2    part1 arm9 boot code 2800000h-ramaddr/2^(2+shift2)
  010h 2    part2 arm7 boot code romaddr/2^(2+shift3) (LZSS compressed)
  012h 2    part2 arm7 boot code 3810000h-ramaddr/2^(2+shift4)
  014h 2    shift amounts, bit0-2=shift1, bit3-5=shift2, bit6-8=shift3,
            bit9-11=shift4, bit12-15=maybe_chipsize/128K
  016h 2    part5 data/gfx romaddr/8 (LZ/huffman compression)
  018h 8    Optional KEY1-encrypted "enPngOFF"=Cartridge KEY2 Disable
            (feature isn't used in any consoles, instead contains timestamp)
  018h 5    Firmware version built timestamp (BCD minute,hour,day,month,year)
  01Dh 1    Console type? (FFh=NDS, 20h=NDS-lite, 43h=iQueDS)
  01Eh 2    Unused (FFh-filled)
  020h 2    User Settings Offset (div8) (usually last 200h flash bytes)
  022h 2    Unknown
  024h 2    Unknown
  026h 2    part5 CRC16 data/gfx
  028h 2    unused (FFh-filled)
</PRE></TD></TR></TBODY></TABLE><BR><B>Wifi Calibration/Settings (located 
directly after Firmware Header)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  02Ah 2    CRC16 (with initial value 0) of [2Ch..2Ch+config_length-1]
  02Ch 2    config_length (usually 0138h, ie. entries 2Ch..163h)
  02Eh 1    Unused        (00h)
  02Fh 1    Wifi version  (00h=v1..v4, 03h=v5, 05h=v6..v7)
  030h 6    Unused        (00h-filled)
  036h 6    48bit MAC address (v1-v5: 0009BFxxxxxx, v6-v7: 001656xxxxxx)
  03Ch 2    list of enabled channels ANDed with 7FFE (Bit1..14 = Channel 1..14)
            (usually 3FFEh, ie. only channel 1..13 enabled)
  03Eh 2    Whatever Flags (usually FFFFh)
  040h 1    RF Chip Type (usually 02h)
  041h 1    RF Bits per entry at 0CEh (usually 18h=24bit=3byte) (Bit7=?)
  042h 1    RF Number of entries at 0CEh (usually 0Ch)
  043h 1    Unknown (usually 01h)
  044h 2    Initial Value for [4808146h]
  046h 2    Initial Value for [4808148h]
  048h 2    Initial Value for [480814Ah]
  04Ah 2    Initial Value for [480814Ch]
  04Ch 2    Initial Value for [4808120h]
  04Eh 2    Initial Value for [4808122h]
  050h 2    Initial Value for [4808154h]
  052h 2    Initial Value for [4808144h]
  054h 2    Initial Value for [4808130h]
  056h 2    Initial Value for [4808132h]
  058h 2    Initial Value for [4808140h]
  05Ah 2    Initial Value for [4808142h]
  05Ch 2    Initial Value for [4808038h]
  05Eh 2    Initial Value for [4808124h]
  060h 2    Initial Value for [4808128h]
  062h 2    Initial Value for [4808150h]
  064h 69h  Initial 8bit values for BB[0..68h]
  0CDh 1    Unused (00h)
</PRE></TD></TR></TBODY></TABLE>Below for Type2 (ie. when [044h]=2) (Mitsumi 
MM3155 and RF9008):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0CEh 24h  Initial 24bit values for RF[0,4,5,6,7,8,9,0Ah,0Bh,1,2,3]
  0F2h 54h  Channel 1..14 2x24bit values for RF[5,6]
  146h 0Eh  Channel 1..14 8bit values for BB[1Eh] (usually somewhat B1h..B7h)
  154h 0Eh  Channel 1..14 8bit values for RF[9].Bit10..14 (usually 10h-filled)
</PRE></TD></TR></TBODY></TABLE>Below for Type3 (ie. when [044h]=3) (Mitsumi 
MM3218):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  --- Type3 values are originated at 0CEh, following addresses depend on:  ---
  1) number of initial values, found at [042h]        ;usually 29h
  2) number of BB indices,     found at [0CEh+[042h]] ;usually 02h
  3) number of RF indices,     found at [043h]        ;usually 02h
  --- Below example addresses assume above values to be set to 29h,02h,02h ---
  0CEh 29h  Initial 8bit values for RF[0..28h]
  0F7h 1    Number of BB indices per channel
  0F8h 1    1st BB index
  0F9h 14   1st BB data for channel 1..14
  107h 1    2nd BB index
  108h 14   2nd BB data for channel 1..14
  116h 1    1st RF index
  117h 14   1st RF data for channel 1..14
  125h 1    2nd RF index
  126h 14   2nd RF data for channel 1..14
  134h 46   Unused (FFh-filled)
</PRE></TD></TR></TBODY></TABLE>Below for both Type2 and Type3:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  162h 1    Unknown (usually 19h..1Ch)
  163h 1    Unused (FFh) (Inside CRC16 region, with config_length=138h)
  164h 9Ch  Unused (FFh-filled) (Outside CRC16 region, with config_length=138h)
</PRE></TD></TR></TBODY></TABLE>Most of the Wifi settings seem to be always the 
same values on all currently existing consoles. Except for:<BR>Values that are 
(obviously) different are the CRC16, and 4th-6th bytes of the MAC address. Also, 
initial values for BB[01h] and BB[1Eh], and channel 1..14 values for BB[1Eh], 
and unknown entry [162h] contain different calibration settings on all 
consoles.<BR>Firmware v5 is having a new wifi ID [2Fh]=03h, and different RF[9] 
setting.<BR>Firmware v6 (dslite) has wifi ID [2Fh]=05h, and same RF[9] setting 
as v5, additionally, v6 and up have different 2nd-3rd bytes of the MAC 
address.<BR><BR>Moreover, a LOT of values are different with Type3 chips (ie. 
when [044h]=3).<BR><BR><B>Note</B><BR>Unlike for Firmware User Settings, the 
Firmware Header (and Wifi Settings) aren't stored in RAM upon boot. So the data 
must be retrieved via SPI bus by software.<BR><BR><B>Note 2</B><BR>Newer 
firmware versions seem to have additional Wifi- and/or Internet-related data at 
FLASH offset 3FA00h or so...?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsfirmwareusersettings></A><FONT size=+2>&nbsp;DS Firmware 
      User Settings</FONT></TD></TR></TBODY></TABLE><BR><B>Current Settings (RAM 
27FFC80h-27FFCFFh)</B><BR><B>User Settings 0 (Firmware 
3FE00h-3FEFFh)</B><BR><B>User Settings 1 (Firmware 3FF00h-3FFFFh)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Size Expl.
  000h  2   Version (5) (Always 5, for all Firmware versions)
  002h  1   Favorite color (0..15) (0=Gray, 1=Brown, etc.)
  003h  1   Birthday month (1..12) (Binary, non-BCD)
  004h  1   Birthday day   (1..31) (Binary, non-BCD)
  005h  1   Not used (zero)
  006h  20  Nickname string in UTF-16 format
  01Ah  2   Nickname length in characters    (0..10)
  01Ch  52  Message string in UTF-16 format
  050h  2   Message length in characters     (0..26)
  052h  1   Alarm hour     (0..23) (Binary, non-BCD)
  053h  1   Alarm minute   (0..59) (Binary, non-BCD)
  054h
  056h  1   80h=enable alarm (huh?), bit 0..6=enable?
  057h      Zero (1 byte)
  058h  2x2 touch-screen calibration point (adc.x1,y1) 12bit ADC-position
  05Ch  2x1 touch-screen calibration point (scr.x1,y1) 8bit pixel-position
  05Eh  2x2 touch-screen calibration point (adc.x2,y2) 12bit ADC-position
  062h  2x1 touch-screen calibration point (scr.x2,y2) 8bit pixel-position
  064h  2   Language and Flags (see below)
  066h  2   Unknown
  068h  4   RTC Offset (difference in seconds when RTC time/date was changed)
  06Ch  4   Not used (FFh-filled, sometimes 00h-filled)
</PRE></TD></TR></TBODY></TABLE>Below not stored in RAM (found only in FLASH 
memory)...<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  070h  1/2 update counter (used to check latest)
  072h  2   CRC16 of entries 00h..6Fh
  074h  8Ch Not used (FFh-filled) (except iQue, see below)
</PRE></TD></TR></TBODY></TABLE>Additional data in chinese iQue DS only:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  074h  4   Unknown (01 01 7E 00) (maybe version and language...?)
  078h  86h Not used (FFh-filled)
  0FEh  2   CRC16 of entries 74h..FDh
</PRE></TD></TR></TBODY></TABLE><BR><B>Language and Flags (Entry 64h)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit
  0..2 Language (0=Japanese, 1=English, 2=French, 3=German,
       4=Italian, 5=Spanish, 6=Chinese, 7=Reserved)
       (the language setting also implies time/data format)
       (chinese is supported by chinese firmware only)
       (chinese is NOT supported by chinese firmware?)
       (or only when chinese cartridge is inserted?)
       (or chinese is defined elsewhere than entry 64h?)
  3    GBA mode screen selection (0=Upper, 1=Lower)
  4-5  Backlight Level    (0..3=Low,Med,High,Max) (DS-Lite only)
  6    Bootmenu Disable   (0=Manual/bootmenu, 1=Autostart game)
  9    User Settings Lost (0=Normal, 1=Prompt/Settings Lost)
  13
  14
 The Health and Safety message is skipped if Bit9=1, or if
 one or more of the following bits is zero: Bits 10,11,13,14,15.
 However, as soon as entering the bootmenu, the Prompt occurs.
</PRE></TD></TR></TBODY></TABLE>Bit9: Prompt for User Info, and Language, and 
Calibration<BR>Bit10: Prompt for User Info<BR>Bit11: Same as Bit10<BR>Bit12: No 
function<BR>Bit13: Prompt for User Info, and Language<BR>Bit14: Same as 
Bit10<BR>Bit15: Same as Bit10<BR><BR>Note: There are two User Settings areas in 
the firmware chip, at offset 3FE00h and 3FF00h, if both areas have valid CRCs, 
then the current/newest area is that whose Update Counter is one bigger than in 
the other/older area.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> IF count1=((count0+1) AND 7Fh) THEN area1=newer ELSE area0=newer
</PRE></TD></TR></TBODY></TABLE>When changing settings, the older area is 
overwritten with new data (and incremented Update Counter). The two areas allow 
to recover previous settings in case of a write-error (eg. on a battery failure 
during write).<BR><BR><B>Battery Removal</B><BR>Even though the battery is 
required only for the RTC (not for the firmware flash memory), most of the 
firmware user settings are reset when removing the battery. This appears to be a 
strange bug-or-feature of the DS bios, at least, fortunately, it still keeps the 
rest of the firmware intact.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsfirmwareextendedsettings></A><FONT size=+2>&nbsp;DS Firmware 
      Extended Settings</FONT></TD></TR></TBODY></TABLE><BR>Extended Settings contain 
some additional information which is not supported by the original firmware 
(current century, date/time formats, temperature calibration, etc.), the 
settings are supported by Nocash Firmware, by the no$gba emulator, and may be 
eventually also supported by other emulators. If present, the values can be used 
by games, otherwise games should use either whatever default settings, or 
contain their own configuration menu.<BR><BR><B>Extended Settings - loaded to 
23FEE00h (aka fragments of NDS9 boot code)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Siz Expl.
  00h  8  ID "XbooInfo"
  08h  2  CRC16 Value [0Ch..0Ch+Length-1]
  0Ah  2  CRC16 Length (from 0Ch and up)
  0Ch  1  Version (currently 01h)
  0Dh  1  Update Count (newer = (older+1) AND FFh)
  0Eh  1  Bootmenu Flags
            Bit6   Important Info  (0=Disable, 1=Enable)
            Bit7   Bootmenu Screen (0=Upper, 1=Lower)
  0Fh  1  GBA Border (0=Black, 1=Gray Line)
  10h  2  Temperature Calibration TP0 ADC value  (x16) (sum of 16 ADC values)
  12h  2  Temperature Calibration TP1 ADC value  (x16) (sum of 16 ADC values)
  14h  2  Temperature Calibration Degrees Kelvin (x100) (0=none)
  16h  1  Temperature Flags
            Bit0-1 Format (0=Celsius, 1=Fahrenheit, 2=Reaumur, 3=Kelvin)
  17h  1  Backlight Intensity (0=0ff .. FFh=Full)
  18h  4  Date Century Offset       (currently 20, for years 2000..2099)
  1Ch  1  Date Month Recovery Value (1..12)
  1Dh  1  Date Day Recovery Value   (1..31)
  1Eh  1  Date Year Recovery Value  (0..99)
  1Fh  1  Date/Time Flags
            Bit0-1 Date Format   (0=YYYY-MM-DD, 1=MM-DD-YYYY, 2=DD-MM-YYYY)
            Bit2   Friendly Date (0=Raw Numeric, 1=With Day/Month Names)
            Bit5   Time DST      (0=Hide DST, 1=Show DST=On/Off)
            Bit6   Time Seconds  (0=Hide Seconds, 1=Show Seconds)
            Bit7   Time Format   (0=24 hour, 1=12 hour)
  20h  1  Date Separator      (Ascii, usually Slash, or Dot)
  21h  1  Time Separator      (Ascii, usually Colon, or Dot)
  22h  1  Decimal Separator   (Ascii, usually Comma, or Dot)
  23h  1  Thousands Separator (Ascii, usually Comma, or Dot)
  24h  1  Daylight Saving Time (Nth)
             Bit 0-3 Activate on (0..4 = Last,1st,2nd,3rd,4th)
             Bit 4-7 Deactivate on (0..4 = Last,1st,2nd,3rd,4th)
  25h  1  Daylight Saving Time (Day)
             Bit 0-3 Activate on (0..7 = Mon,Tue,Wed,Thu,Fri,Sat,Sun,AnyDay)
             Bit 4-7 Deactivate on (0..7 = Mon,Tue,Wed,Thu,Fri,Sat,Sun,AnyDay)
  26h  1  Daylight Saving Time (of Month)
             Bit 0-3 Activate DST in Month   (1..12)
             Bit 4-7 Deactivate DST in Month (1..12)
  27h  1  Daylight Saving Time (Flags)
             Bit 0   Current DST State (0=Off, 1=On)
             Bit 1   Adjust DST Enable (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE>Note: With the original firmware, the memory 
region at 23FEE00h and up contains un-initialized, non-zero-filled data 
(fragments of boot code).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswirelesscommunications></A><FONT size=+2>&nbsp;DS Wireless 
      Communications</FONT></TD></TR></TBODY></TABLE><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiiomap">DS Wifi I/O Map</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswificontrol">DS Wifi 
Control</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dswifiinterrupts">DS 
Wifi Interrupts</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifipowerdownregisters">DS Wifi 
Power-Down Registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifireceivecontrol">DS Wifi Receive 
Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifireceivebuffer">DS Wifi Receive 
Buffer</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifireceivestatistics">DS Wifi 
Receive Statistics</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifitransmitcontrol">DS Wifi 
Transmit Control</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifitransmitbuffers">DS Wifi 
Transmit Buffers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifitransmiterrors">DS Wifi Transmit 
Errors</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dswifistatus">DS Wifi 
Status</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dswifitimers">DS Wifi 
Timers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswificonfigurationports">DS Wifi 
Configuration Ports</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifibasebandchipbb">DS Wifi Baseband 
Chip (BB)</A><BR><A href="http://nocash.emubase.de/gbatek.htm#dswifirfchip">DS 
Wifi RF Chip</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiunknownregisters">DS Wifi 
Unknown Registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiunusedregisters">DS Wifi Unused 
Registers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiinitialization">DS Wifi 
Initialization</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswififlowcharts">DS Wifi 
Flowcharts</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifihardwareheaders">DS Wifi 
Hardware Headers</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifimultiboot">DS Wifi 
Multiboot</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiieee80211frames">DS Wifi 
IEEE802.11 Frames</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiieee80211managmentframestype0">DS 
Wifi IEEE802.11 Managment Frames (Type=0)</A><BR><A 
href="http://nocash.emubase.de/gbatek.htm#dswifiieee80211controlanddataframestype1and2">DS 
Wifi IEEE802.11 Control and Data Frames (Type=1 and 2)</A><BR><BR>2.4GHz band, 
Wireless LAN (WLAN) IEEE802.11b protocol<BR><BR><B>Credits</B><BR>A very large 
part of the DS Wifi chapters is based on Stephen Stair's great DS Wifi document, 
thanks there.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiiomap></A><FONT size=+2>&nbsp;DS Wifi I/O 
  Map</FONT></TD></TR></TBODY></TABLE><BR><B>Notice</B><BR>Wifi Registers &amp; 
RAM cannot be written to by STRB opcodes (ignored).<BR><BR><B>Registers - NDS7 - 
4808000h..4808FFFh</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Dir   Name            r/w  [Init] Description
  000h R     W_ID            ---- [1440] Chip ID (1440h=DS, C340h=DS-Lite)
  004h R/W   W_MODE_RST      9fff [0000] Mode/Reset
  006h R/W   W_MODE_WEP      --7f [0000] Mode/Wep modes
  008h R/W   W_TXSTATCNT     ffff [0000] Beacon Status Request
  00Ah R/W   W_X_00Ah        ffff [0000] [bit7 - ingore rx duplicates]
  010h R/W   W_IF            ackk [0000] Wifi Interrupt Request Flags
  012h R/W   W_IE            ffff [0000] Wifi Interrupt Enable
  018h R/W   W_MACADDR_0     ffff [0000] Hardware MAC Address (first 2 bytes)
  01Ah R/W   W_MACADDR_1     ffff [0000] Hardware MAC Address (next 2 bytes)
  01Ch R/W   W_MACADDR_2     ffff [0000] Hardware MAC Address (last 2 bytes)
  020h R/W   W_BSSID_0       ffff [0000] BSSID (first 2 bytes)
  022h R/W   W_BSSID_1       ffff [0000] BSSID (next 2 bytes)
  024h R/W   W_BSSID_2       ffff [0000] BSSID (last 2 bytes)
  028h R/W   W_AID_LOW       ---f [0000] usually as lower 4bit of AID value
  02Ah R/W   W_AID_FULL      -7ff [0000] AID value assigned by a BSS.
  02Ch R/W   W_TX_RETRYLIMIT ffff [0707] Tx Retry Limit (set from 0x00-0xFF)
  02Eh R/W   W_INTERNAL      ---1 [0000]
  030h R/W   W_RXCNT         ff0e [0000] Receive control
  032h R/W   W_WEP_CNT       ffff [0000] WEP engine enable
  034h R?    W_INTERNAL      0000 [0000] bit0,1 (see port 004h and 1A0h)
</PRE></TD></TR></TBODY></TABLE><B>Power-Down Registers (and Random 
Generator)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  036h R/W   W_POWER_US      ---3 [0001]
  038h R/W   W_POWER_TX      ---7 [0003]
  03Ch R/W   W_POWERSTATE    -r-2 [0200]
  040h R/W   W_POWERFORCE    8--1 [0000]
  044h R     W_RANDOM        0xxx [0xxx]
  048h R/W   W_POWER_?       ---3 [0000]
</PRE></TD></TR></TBODY></TABLE><B>WLAN Memory Ports</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  050h R/W   W_RXBUF_BEGIN   ffff [4000]
  052h R/W   W_RXBUF_END     ffff [4800]
  054h R     W_RXBUF_WRCSR   0rrr [0000]
  056h R/W   W_RXBUF_WR_ADDR -fff [0000]
  058h R/W   W_RXBUF_RD_ADDR 1ffe [0000]
  05Ah R/W   W_RXBUF_READCSR -fff [0000]
  05Ch R/W   W_RXBUF_COUNT   -fff [0000]
  060h R     W_RXBUF_RD_DATA rrrr [xxxx]
  062h R/W   W_RXBUF_GAP     1ffe [0000]
  064h R/W   W_RXBUF_GAPDISP -fff [0000]
  068h R/W   W_TXBUF_WR_ADDR 1ffe [0000]
  06Ch R/W   W_TXBUF_COUNT   -fff [0000]
  070h W     W_TXBUF_WR_DATA xxxx [xxxx]
  074h R/W   W_TXBUF_GAP     1ffe [0000]
  076h R/W   W_TXBUF_GAPDISP 0fff [0000]
</PRE></TD></TR></TBODY></TABLE><B>xxx</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  078h W     W_INTERNAL      mirr [mirr] Read: Mirror of 068h
  080h R/W   W_TXBUF_BEACON  ffff [0000] Beacon Transmit Location
  084h R/W   W_TXBUF_TIM     --ff [0000] Beacon TIM Index in Frame Body
  088h R/W   W_LISTENCOUNT   --ff [0000] Listen Count
  08Ch R/W   W_BEACONINT     -3ff [0064] Beacon Interval
  08Eh R/W   W_LISTENINT     --ff [0000] Listen Interval
  090h R/W   W_TXBUF_EXTRA   ffff [0000]    (used by firmware part4)
  094h R/W x                 ffff [0000] ?  (used by firmware part4)
  098h R   x                 0000 [0000]    (used by firmware part4)
  09Ch R/W   W_INTERNAL      ffff [0050] value 4x00h --&gt; preamble+x*12h us?
  0A0h R/W   W_TXBUF_LOC1    ffff [0000]
  0A4h R/W   W_TXBUF_LOC2    ffff [0000]
  0A8h R/W   W_TXBUF_LOC3    ffff [0000]
  0ACh W     W_TXREQ_RESET   fixx [0050]
  0AEh W     W_TXREQ_SET     fixx [0050]
  0B0h R     W_TXREQ_READ    --1f [0010]
  0B4h W     W_TXBUF_RESET   0000 [0000]    (used by firmware part4)
  0B6h R     W_TXBUSY        0000 [0000]    (used by firmware part4)
  0B8h R     W_TXSTAT        0000 [0000]
  0BAh ?     W_INTERNAL      0000 [0000]
  0BCh R/W   W_PREAMBLE      ---3 [0001]
  0C0h R/W x                 ffff [0000]    (used by firmware part4)
  0C4h R/W x                 ffff [0000]    (used by firmware part4)
  0C8h ?     W_INTERNAL      0000 [0000]
  0D0h R/W   W_RXFILTER      1fff [0401]
  0D4h R/W   W_CONFIG_0D4h   ---3 [0001]
  0D8h R/W   W_CONFIG_0D8h   -fff [0004]
  0DAh R/W   W_CONFIG_0DAh   ffff [0602]
  0E0h R/W   W_RXFILTER2     ---f [0008]
</PRE></TD></TR></TBODY></TABLE><B>Wifi Timers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0E8h R/W   W_US_COUNTCNT   ---1 [0000] Microsecond counter enable
  0EAh R/W   W_US_COMPARECNT ---1 [0000] Microsecond compare enable
  0ECh R/W   W_CONFIG_0ECh   3f1f [3F03]
  0EEh R/W   W_EXTRACOUNTCNT ---1 [0001]
  0F0h R/W   W_US_COMPARE0   fc-- [FC00] Microsecond compare, bits 0-15
  0F2h R/W   W_US_COMPARE1   ffff [FFFF] Microsecond compare, bits 16-31
  0F4h R/W   W_US_COMPARE2   ffff [FFFF] Microsecond compare, bits 32-47
  0F6h R/W   W_US_COMPARE3   ffff [FFFF] Microsecond compare, bits 48-63
  0F8h R/W   W_US_COUNT0     ffff [0000] Microsecond counter, bits 0-15
  0FAh R/W   W_US_COUNT1     ffff [0000] Microsecond counter, bits 16-31
  0FCh R/W   W_US_COUNT2     ffff [0000] Microsecond counter, bits 32-47
  0FEh R/W   W_US_COUNT3     ffff [0000] Microsecond counter, bits 48-63
  100h ?     W_INTERNAL      0000 [0000]
  102h ?     W_INTERNAL      0000 [0000]
  104h ?     W_INTERNAL      0000 [0000]
  106h ?     W_INTERNAL      0000 [0000]
  10Ch R/W   W_CONTENTFREE   ffff [0000] ...
  110h R/W   W_PRE_BEACON    ffff [0000]
  118h R/W   W_EXTRACOUNT    ffff [0000]
  11Ch R/W   W_BEACONCOUNT1  ffff [0000] decreases; reloaded with W_BEACONINT
</PRE></TD></TR></TBODY></TABLE><B>Configuration Ports (and some other 
Registers)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  120h R/W   W_CONFIG_120h   81ff [0048] ...init from firmware[04Ch]
  122h R/W   W_CONFIG_122h   ffff [4840] ...init from firmware[04Eh]
  124h R/W   W_CONFIG_124h   ffff [0000] ...init from firmware[05Eh], or 00C8h
  126h ?     W_INTERNAL      fixx [ 0080]
  128h R/W   W_CONFIG_128h   ffff [0000] ...init from firmware[060h], or 07D0h
  12Ah ?     W_INTERNAL      fixx [1000] lower 12bit are same as W_CONFIG_128h
  130h R/W   W_CONFIG_130h   -fff [0142] ...init from firmware[054h]
  132h R/W   W_CONFIG_132h   8fff [8064] ...init from firmware[056h]
  134h R/W   W_BEACONCOUNT2  ffff [FFFF] ...
  140h R/W   W_CONFIG_140h   ffff [0000] ...init from firmware[058h], or xx
  142h R/W   W_CONFIG_142h   ffff [2443] ...init from firmware[05Ah]
  144h R/W   W_CONFIG_144h   --ff [0042] ...init from firmware[052h]
  146h R/W   W_CONFIG_146h   --ff [0016] ...init from firmware[044h]
  148h R/W   W_CONFIG_148h   --ff [0016] ...init from firmware[046h]
  14Ah R/W   W_CONFIG_14Ah   --ff [0016] ...init from firmware[048h]
  14Ch R/W   W_CONFIG_14Ch   ffff [162C] ...init from firmware[04Ah]
  150h R/W   W_CONFIG_150h   ff3f [0204] ...init from firmware[062h], or 202h
  154h R/W   W_CONFIG_154h   7a7f [0058] ...init from firmware[050h]
</PRE></TD></TR></TBODY></TABLE><B>Baseband Chip Ports</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  158h W     W_BB_CNT        mirr [00B5] BB Access Start/Direction/Index
  15Ah W     W_BB_WRITE      ???? [0000] BB Access data byte to write
  15Ch R     W_BB_READ       00rr [00B5] BB Access data byte read
  15Eh R     W_BB_BUSY       000r [0000] BB Access Busy flag
  160h R/W   W_BB_MODE       41-- [0100] BB Access Mode
  168h R/W   W_BB_POWER      8--f [800D] BB Access Powerdown
</PRE></TD></TR></TBODY></TABLE><B>Internal Stuff</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  16Ah ?     W_INTERNAL      0000 [0001] (or 0000h?)
  170h ?     W_INTERNAL      0000 [0000]
  172h ?     W_INTERNAL      0000 [0000]
  174h ?     W_INTERNAL      0000 [0000]
  176h ?     W_INTERNAL      0000 [0000]
  178h W     W_INTERNAL      fixx [0800] Read: mirror of 17Ch
</PRE></TD></TR></TBODY></TABLE><B>RF Chip Ports</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  17Ch R/W   W_RF_DATA2      ffff [0800]
  17Eh R/W   W_RF_DATA1      ffff [C008]
  180h R     W_RF_BUSY       000r [0000]
  184h R/W   W_RF_CNT        413f [0018]
</PRE></TD></TR></TBODY></TABLE><B>xxx</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  190h R/W   W_INTERNAL      ffff [0000]
  194h R/W x                 ---7 [0000]     (used by firmware part4) (0 or 6)
  198h R/W   W_INTERNAL      ---f [0000]
  19Ch R     W_RF_PINS       fixx [0004]
  1A0h R/W x                 -933 [0000] (used by firmware part4) (0 or 823h)
  1A2h R/W x                 ---3 [0001] (used by firmware part4)
  1A4h R/W x                 ffff [0000] "Rate used when signal test..."
</PRE></TD></TR></TBODY></TABLE><B>Wifi Statistics</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1A8h R     W_RXSTAT_INC_IF rrrr [0000] Statistics Increment Flags
  1AAh R/W   W_RXSTAT_INC_IE ffff [0000] Statistics Increment IRQ Enable
  1ACh R     W_RXSTAT_OVF_IF rrrr [0000] Statistics Half-Overflow Flags
  1AEh R/W   W_RXSTAT_OVF_IE ffff [0000] Statistics Half-Overflow IRQ Enable
  1B0h R/W   W_RXSTAT        --ff [0000]
  1B2h R/W   W_RXSTAT        ffff [0000] RX_LengthErrorCount RX_RateErrorCount
  1B4h R/W   W_RXSTAT        rrff [0000] ... firmware uses also MSB ... ?
  1B6h R/W   W_RXSTAT        ffff [0000]
  1B8h R/W   W_RXSTAT        --ff [0000]
  1BAh R/W   W_RXSTAT        --ff [0000]
  1BCh R/W   W_RXSTAT        ffff [0000]
  1BEh R/W   W_RXSTAT        ffff [0000]
  1C0h R/W   W_TX_ERR_COUNT  --ff [0000] TransmitErrorCount
  1C4h R     W_RX_COUNT      fixx [0000]
</PRE></TD></TR></TBODY></TABLE>[1D0 - 1DE are 15 entries related to multiplayer 
response errors]<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1D0h R/W   W_STAT          ff-- [0000]
  1D2h R/W   W_STAT          ffff [0000]
  1D4h R/W   W_STAT          ffff [0000]
  1D6h R/W   W_STAT          ffff [0000]
  1D8h R/W   W_STAT          ffff [0000]
  1DAh R/W   W_STAT          ffff [0000]
  1DCh R/W   W_STAT          ffff [0000]
  1DEh R/W   W_STAT          ffff [0000]
</PRE></TD></TR></TBODY></TABLE><B>Internal Diagnostics Registers (usually not 
used for anything)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1F0h R/W   W_INTERNAL      ---3 [0000]
  204h ?     W_INTERNAL      fixx [0000]
  208h ?     W_INTERNAL      fixx [0000]
  20Ch W     W_INTERNAL      fixx [0050]
  210h R     W_TX_SEQNO      fixx [0000]
  214h R     W_RF_STATUS     XXXX [0009]    (used by firmware part4)
  21Ch W     W_IF_SET        fbff [0000] Force Interrupt (set bits in W_IF).
  220h R/W   W_INTERNAL      ffff [0000] "Has something to do with whether the
                                         packet is ignored or allowed by the
                                         packet filtering system"
                                          Bit0-1: Enable/Disable WifiRAM
                                          (nothing to do with filtering, just
                                          locks memory at 4000h-5FFFh)
  224h R/W   W_INTERNAL      ---3 [0003]
  228h W   x                 fixx [0000]    (used by firmware part4) (bit3)
  230h R/W   W_INTERNAL      --ff [0047]
  234h R/W   W_INTERNAL      -eff [0EFF]
  238h R/W   W_INTERNAL      ffff [0000]
  23Ch ?     W_INTERNAL      fixx [0000] like W_TXSTAT, but ONLY for beacons?
  244h R/W x                 ffff [0000]    (used by firmware part4)
  248h R/W   W_INTERNAL      ffff [0000]
  24Ch ?     W_INTERNAL      fixx [0000]
  24Eh ?     W_INTERNAL      fixx [0000]
  250h ?     W_INTERNAL      fixx [0000]
  254h ?     W_CONFIG_254h   fixx [0000] (is EEEEh on DS-Lite)
  258h ?     W_INTERNAL      fixx [0000]
  25Ch ?     W_INTERNAL      fixx [0000]
  260h ?     W_INTERNAL      fixx [ 0FEF]
  264h ?     W_INTERNAL      fixx [0000]
  268h R   x W_RXUNITS       fixx [0005]
  270h ?     W_INTERNAL      fixx [0000]
  274h ?     W_INTERNAL      fixx [ 0001]
  278h R/W   W_INTERNAL      ffff [000F]
  27Ch ?     W_INTERNAL      fixx [ 000A]
  290h (R/W)  x              fixx [FFFF] bit 0 = ?  (used by firmware part4)
  298h W     W_INTERNAL      fixx [0000]
  2A0h R/W   W_INTERNAL      ffff [0000]
  2A2h R     W_INTERNAL      XXXX [7FFF] 15bit shift reg (used during tx...?)
  2A4h ?     W_INTERNAL      fixx [0000]
  2A8h W     W_INTERNAL      fixx [0000]
  2ACh ?     W_INTERNAL      fixx [ 0038]
  2B0h W     W_INTERNAL      fixx [0000]
  2B4h R/W   W_INTERNAL      -1-3 [0000]
  2B8h ?     W_INTERNAL      fixx [0000]
  2C0h R/W   W_INTERNAL      ---1 [0000]
  2C4h ?     W_INTERNAL      fixx [ 000A]
  2C8h ?     W_INTERNAL      fixx [0000]
  2CCh ?     W_INTERNAL      fixx [0000]
  2D0h DIS   W_INTERNAL                  ;"W_POWERACK" (not used by firmware)
                                         ;normally DISABLED (except on FORCE)
  2F0h R/W   W_INTERNAL      ffff [0000]
  2F2h R/W   W_INTERNAL      ffff [0000]
  2F4h R/W   W_INTERNAL      ffff [0000]
  2F6h R/W   W_INTERNAL      ffff [0000]
</PRE></TD></TR></TBODY></TABLE>All other ports in range 000h..FFFh are 
unused.<BR>All registers marked as "W_INTERNAL" aren't used by Firmware part4, 
and are probably unimportant, except for whatever special diagnostics 
purposes.<BR>Reading from write-only ports (W) often mirrors to data from other 
ports.<BR><BR>Additionally, there are 69h Baseband Chip Registers (BB), and 0Ch 
RF Chip Registers (see BB and RF chapters).<BR><BR>For Wifi Power Managment 
(POWCNT2), for Wifi Waitstates (WIFIWAITCNT), and for the Power LED Blink 
Feature (conventionally used to indicate Wifi activity) see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dspowermanagement">DS Power 
Management</A><BR><BR>For Wifi Configuration and Calibration data in Firmware 
Header, see:<BR><A 
href="http://nocash.emubase.de/gbatek.htm#dscartridgesencryptionfirmware">DS 
Cartridges, Encryption, Firmware</A><BR><BR><B>Wifi RAM - NDS7 - Memory 
(4804000h..4805FFFh)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4804000h W_MACMEM RX/TX Buffers (2000h bytes) (excluding below specials)
  4805F60h Used for something, not included in the rx circular buffer.
  4805F80h W_WEPKEY_0 (32 bytes)
  4805FA0h W_WEPKEY_1 (32 bytes)
  4805FC0h W_WEPKEY_2 (32 bytes)
  4805FE0h W_WEPKEY_3 (32 bytes)
</PRE></TD></TR></TBODY></TABLE>Unlike all other NDS memory, Wifi RAM is left 
uninitialized after boot.<BR><BR><B>5F80h - W_WEPKEY_0 thru W_WEPKEY_3 - Wifi 
WEP keys (R/W)</B><BR>These WEP key slots store the WEP keys that are used for 
encryption for 802.11 keys IDs 0-3.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswificontrol></A><FONT size=+2>&nbsp;DS Wifi 
  Control</FONT></TD></TR></TBODY></TABLE><BR><B>000h - W_ID - Wifi Chip ID 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15   Chip ID (1440h on NDS, C340h on NDS-lite)
</PRE></TD></TR></TBODY></TABLE>The NDS-lite is more or less backwards 
compatible with the original NDS (the W_RXBUF_GAPDISP and W_TXBUF_GAPDISP are 
different, and most of the garbage effects on unused/mirrored ports are 
different, too).<BR><BR><B>004h - W_MODE_RST - Wifi Hardware mode / reset 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Adjust some ports (0/1=see lists below) (R/W)
        TX Master Enable for LOC1..3 and Beacon  (0=Disable, 1=Enable)
  1-12  Unknown (R/W)
  13    Reset some ports (0=No change, 1=Reset/see list below) (Write-Only)
  14    Reset some ports (0=No change, 1=Reset/see list below) (Write-Only)
  15    Unknown (R/W)
</PRE></TD></TR></TBODY></TABLE><BR><B>006h - W_MODE_WEP - Wifi Software mode / 
Wep mode (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-2   specify a software mode for wifi operation
        (may be related to hardware but a correlation has not yet been found)
  3-5   specify the hardware WEP mode
        0=no WEP, 1=64bit WEP (48bit key), and 3=128bit WEP.
        (Values 2 and 4 exist too, but are nonstandard)
  6     Unknown
  8-15  Always zero
</PRE></TD></TR></TBODY></TABLE><BR><B>018h - W_MACADDR_0 - MAC Address 
(R/W)</B><BR><B>01Ah - W_MACADDR_1 - MAC Address (R/W)</B><BR><B>01Ch - 
W_MACADDR_2 - MAC Address (R/W)</B><BR>48bit MAC Address of the console. Should 
be initialized from firmware[036h]. The hardware receives only packets that are 
sent to this address (or to group addresses, like 
FF:FF:FF:FF:FF:FF).<BR><BR><B>020h - W_BSSID_0 - BSSID (R/W)</B><BR><B>022h - 
W_BSSID_1 - BSSID (R/W)</B><BR><B>024h - W_BSSID_2 - BSSID (R/W)</B><BR>48bit 
BSSID stored here. Ie. the MAC address of the host, obtained from Beacon frames 
(on the host itself, that should be just same as W_MACADDR). See 
W_RXFILTER.<BR><BR><B>028h - W_AID_LOW (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-3   Maybe player-number, assuming that HW supports such? (1..15, or 0)
  Bit4-15  Not used
</PRE></TD></TR></TBODY></TABLE>Usually set equal to the lower 4bit of the 
W_AID_FULL value.<BR><BR><B>02Ah - W_AID_FULL - Association ID (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0-10  Association ID (AID) (1..2007, or zero)
  Bit11-15 Not used
</PRE></TD></TR></TBODY></TABLE><BR><B>032h - W_WEP_CNT - WEP Engine Enable 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-14  Unknown (usually zero)
  15    WEP Engine Enable  (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE>[expl. I - bit15 enables/disables WEP processing 
of sent/received packets]<BR>[expl. II - bit15 enables wep processing on packets 
which bear the WEP flag in the 802.11 header]<BR>[expl. III - bit15 seems to 
react on 0-to-1 transitions]<BR><BR><B>044h - W_RANDOM - Random Generator 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-10  Random
  11-15 Not used (zero)
</PRE></TD></TR></TBODY></TABLE>The random generator is updated at 33.51MHz 
rate, as such:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  X = (X AND 1) XOR (X ROL 1)  ;(rotation within 11bit range)
</PRE></TD></TR></TBODY></TABLE>That random sequence goes through 5FDh different 
values before it restarts.<BR>When reading from the random register, the old 
latched value is returned to the CPU, and the new current random value is then 
latched, so reads always return the older value, timed from the previous 
read.<BR>Occassionally, about once every some thousand reads, the latching 
appears to occur 4 cycles earlier than normally, so the value on the next read 
will be 4 cycles older than expected.<BR>The random register has ACTIVE 
mirrors.<BR><BR><B>0BCh - W_PREAMBLE - Preamble Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit   Dir  Expl.
  0     R/W  Unknown                    (this does NOT affect TX)
  1     R/W  Preamble (0=Long, 1=Short) (this does NOT affect TX)
  2     W    Preamble (0=Long, 1=Short) (this does affect TX) (only at 2Mbit/s)
  3-15  -    Always zero
</PRE></TD></TR></TBODY></TABLE>Short preamble works only with 2Mbit/s transfer 
rate (ie. when set like so in TX hardware header). 1Mbit/s rate always uses long 
preamble.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Type   Carrier Signal  SFD Value     PLCP Header     Data
  Long   128bit, 1Mbit   16bit, 1Mbit  48bit, 1Mbit    N bits, 1Mbit or 2Mbit
  Short  56bit, 1Mbit    16bit, 1Mbit  48bit, 2Mbit    N bits, 2Mbit
</PRE></TD></TR></TBODY></TABLE>Length of the Carrier+SFD+PLCP part is thus 
192us (long) or 96us (short).<BR>Note: The Carrier+SFD+PLCP part is sent between 
IRQ14 and IRQ07 (not between IRQ07 and IRQ01).<BR><BR><B>Writing "0-then-1" to 
W_MODE_RST.Bit0 does reset following ports:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [034h]=0002h ;W_INTERNAL
  [19Ch]=0046h ;W_RF_PINS
  [214h]=0009h ;W_RF_STATUS
  [27Ch]=0005h ;W_INTERNAL
  [2A2h]=?     ;...unstable?
</PRE></TD></TR></TBODY></TABLE><BR><B>Writing "1-then-0" to W_MODE_RST.Bit0 
does reset following ports:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [27Ch]=000Ah ;W_INTERNAL
</PRE></TD></TR></TBODY></TABLE><BR><B>Writing "1" to W_MODE_RST.Bit13 does 
reset following ports:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [056h]=0000h ;W_RXBUF_WR_ADDR
  [0C0h]=0000h ; x
  [0C4h]=0000h ; x
  [1A4h]=0000h ; x
  [278h]=000Fh ;W_INTERNAL
  ...Also, following may be affected (results are unstable though)...
  [0AEh]=?     ;or rather the actual port (which it is an mirror of)
  [0BAh]=?     ;W_INTERNAL (occassionally unstable)
  [204h]=?     ;W_INTERNAL
  [25Ch]=?     ;W_INTERNAL
  [268h]=?     ;W_RXUNITS
  [274h]=?     ;W_INTERNAL
</PRE></TD></TR></TBODY></TABLE><BR><B>Writing "1" to W_MODE_RST.Bit14 does 
reset following ports:</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [006h]=0000h ;W_MODE_WEP
  [008h]=0000h ;W_TXSTATCNT
  [00Ah]=0000h ;W_X_00Ah
  [018h]=0000h ;W_MACADDR_0
  [01Ah]=0000h ;W_MACADDR_1
  [01Ch]=0000h ;W_MACADDR_2
  [020h]=0000h ;W_BSSID_0
  [022h]=0000h ;W_BSSID_1
  [024h]=0000h ;W_BSSID_2
  [028h]=0000h ;W_AID_LOW
  [02Ah]=0000h ;W_AID_FULL
  [02Ch]=0707h ;W_TX_RETRYLIMIT
  [02Eh]=0000h ;W_INTERNAL
  [050h]=4000h ;W_RXBUF_BEGIN
  [052h]=4800h ;W_RXBUF_END
  [084h]=0000h ;W_TXBUF_TIM
  [0BCh]=0001h ;W_PREAMBLE
  [0D0h]=0401h ;W_RXFILTER
  [0D4h]=0001h ;W_CONFIG_0D4h
  [0E0h]=0008h ;W_RXFILTER2
  [0ECh]=3F03h ;W_CONFIG_0ECh
  [194h]=0000h ; x
  [198h]=0000h ;W_INTERNAL
  [1A2h]=0001h ; x
  [224h]=0003h ;W_INTERNAL
  [230h]=0047h ;W_INTERNAL
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiinterrupts></A><FONT size=+2>&nbsp;DS Wifi 
      Interrupts</FONT></TD></TR></TBODY></TABLE><BR><B>010h - W_IF - Wifi Interrupt 
Request Flags (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0   Receive Complete  (packet received and stored in the RX fifo)
  1   Transmit Complete (packet is done being transmitted) (no matter if error)
  2   Receive Event Increment      (IRQ02, see W_RXSTAT_INC_IE)
  3   Transmit Error Increment     (IRQ03, see W_TX_ERR_COUNT)
  4   Receive Event Half-Overflow  (IRQ04, see W_RXSTAT_OVF_IE)
  5   Transmit Error Half-Overflow (IRQ05, see W_TX_ERR_COUNT.Bit7)
  6   Start Receive     (a packet has just started to be received)
  7   Start Transmit    (a packet has just started to be transmitted)
  8   Txbuf Count Expired  (IRQ08, see W_TXBUF_COUNT)
  9   Rxbuf Count Expired  (IRQ09, see W_RXBUF_COUNT)
  10  Not used (always zero, even when trying to set it with W_IF_SET)
  11  RF Wakeup            (IRQ11, see W_POWERSTATE)
  12  ?                    (IRQ12, see W_EXTRACOUNT)
  13  Post-Beacon Timeslot (IRQ13, see W_BEACONCOUNT2)
  14  Beacon Timeslot      (IRQ14, see W_BEACONCOUNT1/W_US_COMPARE)
  15  Pre-Beacon Timeslot  (IRQ15, see W_BEACONCOUNT1/W_PRE_BEACON)
</PRE></TD></TR></TBODY></TABLE>Write a '1' to a bit to clear it.<BR>The 
Transmit Start/Complete bits (Bit7,1) are set for EACH packet (including 
beacons, and including retries).<BR><BR><B>012h - W_IE - Wifi Interrupt Enable 
Flags (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Enable Flags, same bits as W_IF  (0=Disable, 1=Enable)
</PRE></TD></TR></TBODY></TABLE>In W_IE, Bit10 is R/W, but seems to have no 
function since IRQ10 doesn't exist.<BR><BR><B>21Ch - W_IF_SET (W_INTERNAL) - 
Force Wifi Interrupt Flags (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Set corresponding bits in W_IF  (0=No change, 1=Set Bit)
</PRE></TD></TR></TBODY></TABLE>Notes: Bit10 cannot be set since no IRQ10 
exists. This register does only set IRQ flags, but without performing special 
actions (such like W_BEACONCOUNT1 and W_BEACONCOUNT2 reloads that occur on real 
IRQ14's).<BR><BR><B>Wifi Primary IRQ Flag (IF.Bit24, Port 
4000214h)</B><BR>IF.Bit24 gets set &lt;only&gt; when (W_IF AND W_IE) changes 
from 0000h to non-zero.<BR>IF.Bit24 can be reset (ack) &lt;even&gt; when (W_IF 
AND W_IE) is still non-zero.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE><B>  Caution  Caution  Caution  Caution  Caution</B>
  That means, when acknowledging IF.Bit24, then NO FURTHER wifi IRQs
  will be executed whilst and as long as (W_IF AND W_IE) is non-zero.
</PRE></TD></TR></TBODY></TABLE>One work-around is to process/acknowledge ALL 
wifi IRQs in a loop, including further IRQs that may occur inside of that loop, 
until (W_IF AND W_IE) becomes 0000h.<BR>Another work-around (for single IRQs) 
would be to acknowledge IF and W_IF, and then to set W_IE temporarily to 0000h, 
and then back to the old W_IE setting.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifipowerdownregisters></A><FONT size=+2>&nbsp;DS Wifi 
      Power-Down Registers</FONT></TD></TR></TBODY></TABLE><BR><B>036h - W_POWER_US 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Disable W_US_COUNT and W_BB_ports  (0=Enable, 1=Disable)
  1     Unknown (usually 0)
  2-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Bit0=0 enables RFU by setting RFU.Pin11=HIGH, 
which activates the 22.000MHz oscillator on the RFU board, the 22MHz clock is 
then output to RFU.Pin26.<BR><BR><B>038h - W_POWER_TX 
(R/W)</B><BR>transmit-related power save or sth<BR>init from firmware[05Ch]<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Auto Wakeup (1=Leave Idle Mode a while after IRQ15)
  1     Auto Sleep  (0=Enter Idle Mode on IRQ13)
  2     Unknown
  3     Unknown (Write-only) (used by firmware)
  4-15  Always zero
</PRE></TD></TR></TBODY></TABLE><BR><B>03Ch - W_POWERSTATE (R/W)/(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Unknown (usually 0)                         (R/W)
  1     Request Power Enable (0=No, 1=Yes/queued)   (R/W, but not always)
  2-7   Always zero
  8     Indicates that Bit9 is about the be cleared (Read only)
  9     Current power state (0=Enabled, 1=Disabled) (Read only)
  10-15 Always zero
</PRE></TD></TR></TBODY></TABLE>[value =1: queue disable power state] ;&lt;-- 
seems to be incorrect<BR>[value =2: queue enable power state] ;&lt;-- seems to 
be correct<BR>Enabling causes wakeup interrupt (IRQ11).<BR>Note: That queue 
stuff seems to work only if W_POWER_US=0 and W_MODE_RST=1.<BR><BR><B>040h - 
W_POWERFORCE - Force Power State (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     New value for W_POWERSTATE.Bit9  (0=Clear/Delayed, 1=Set/Immediately)
  1-14  Always zero
  15    Apply Bit0 to W_POWERSTATE.Bit9  (0=No, 1=Yes)
</PRE></TD></TR></TBODY></TABLE>Setting W_POWERFORCE=8000h whilst 
W_POWERSTATE.Bit9=1 acts delayed:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_POWERSTATE.Bit8 gets set to indicate the pending operation,
  while pending, changes to W_POWERFORCE aren't applied to W_POWERSTATE,
  while pending, W_POWERACK becomes Read/Write-able,
  writing 0000h to W_POWERACK does clear W_POWERSTATE.Bit8,
  and does apply POWERFORCE.Bit0 to W_POWERSTATE.Bit9
  and does deactivate Port W_POWERACK again.
</PRE></TD></TR></TBODY></TABLE>(After that sequence, the hardware seems to be 
messed up)<BR><BR><B>048h - W_POWER_? (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Unknown
  1     Unknown
  2-15  Always zero
</PRE></TD></TR></TBODY></TABLE>At whatever time (during transmit or so) it gets 
set to 0003h by hardware.<BR><BR>See also: POWCNT2, W_BB_POWER.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifireceivecontrol></A><FONT size=+2>&nbsp;DS Wifi Receive 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>030h - W_RXCNT - Wifi Receive 
Control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Description
  0    Latch registers for RX FIFO (Write-only) (always reads as zero)
  1-3  Unknown                     (R/W)
  4-6  Always zero
  7    Related to Port 094h        (Write-only) (always reads as zero)
  8-14 Unknown                     (R/W)
  15   Enable Queuing received data to RX FIFO (R/W)
</PRE></TD></TR></TBODY></TABLE>Latched registers include: W_RXBUF_BEGIN, 
W_RXBUF_END and also W_RXBUF_WRCSR=W_RXBUF_WR_ADDR<BR><BR><B>0D0h - W_RXFILTER - 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Description
  0     (0=Insist on W_BSSID, 1=Accept no matter of W_BSSID)
  1-6   Unknown (usually zero)
  7     Unknown (0 or 1)
  8     Unknown (0 or 1)
  9     Unknown (0 or 1)
  10    Unknown (0 or 1)       (when set, receives beacons, and maybe others)
  11    Unknown (usually zero)
  12    (0=Normal, 1=Accept even whatever garbage)
  13-15 Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>Specifies what packets to allow.<BR>0000h = 
Disable receive.<BR>FFFFh = Enable receive.<BR>0400h = Receives managment frames 
(and possibly others, too)<BR><BR><B>0E0h - W_RXFILTER2 - (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Unknown (0=Receive Data Frames, 1=Ignore Data Frames) (?)
  1     Unknown
  2     Unknown
  3     Unknown (usually set)
  4-15  Not used (always zero)
</PRE></TD></TR></TBODY></TABLE>Firmware writes values 08h, 0Bh, 0Dh (aka 1000b, 
1011b, 1101b).<BR>Firmware usually has bit0 set, even when receiving data 
frames, so, in some situations data frames seem to pass-through even when bit0 
is set...? Possibly that situation is when W_BSSID 
matches...?<BR>Control/PS-Poll frames seem to be passed always (even if 
W_RXFILTER2=0Fh).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifireceivebuffer></A><FONT size=+2>&nbsp;DS Wifi Receive 
      Buffer</FONT></TD></TR></TBODY></TABLE><BR>The dimensions of the circular Buffer 
are set with BEGIN/END values, hardware automatically wraps to BEGIN when an 
incremented pointer hits END address.<BR><BR><B>Write Area</B><BR>Memory between 
WRCSR and READCSR is free for receiving data, the hardware writes incoming 
packets to this region (to WRCSR and up) (but without exceeding READCSR), once 
when it has successfully received a complete packet, the hardware moves WRCSR 
after the packet (aligned to a 4-byte boundary).<BR><BR><B>Read 
Area</B><BR>Memory between READCSR and WRCSR contains received data, which can 
be read by the CPU via RD_ADDR and RD_DATA registers (or directly from memory). 
Once when having processed that data, the CPU must set READCSR to the end of 
it.<BR><BR><B>050h - W_RXBUF_BEGIN - Wifi RX Fifo start location 
(R/W)</B><BR><B>052h - W_RXBUF_END - Wifi RX Fifo end location (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Byte-offset in Wifi Memory (usually 4000h..5FFEh)
</PRE></TD></TR></TBODY></TABLE>Although the full 16bit are R/W, only the 12bit 
halfword offset in Bit1-12 is actually used, the other bits seem to have no 
effect.<BR>Some or all (?) of the below incrementing registers are automatically 
matched to begin/end, that is, after incrementing, IF adr=end THEN 
adr=begin.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>   W_RXBUF_BEGIN and W_RXBUF_END are reportedly "latched"
   when bottom bit of W_RXCNT is set
   no idea if/where/what is "latched" to/from what location,
   eventually means that above register settings are forwarded to internal
   receive registers..?
</PRE></TD></TR></TBODY></TABLE><BR><B>054h - W_RXBUF_WRCSR - Wifi RX Fifo Write 
or "end" cursor (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Address in RAM
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>This is a hardware controlled write location - 
it shows where the next packet will be written..<BR><BR><B>056h - 
W_RXBUF_WR_ADDR - Wifi RX Fifo Write Cursor Latch value (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Address in RAM
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>This is a value that is latched into 
W_RXBUF_WRCSR, when the W_RXCNT latch bit (W_RXCNT.Bit0) is 
written.<BR><BR><B>058h - W_RXBUF_RD_ADDR - Wifi CircBuf Read Address 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Always zero
  1-12  Halfword Address in RAM for reading via W_RXBUF_RD_DATA
  13-15 Always zero
</PRE></TD></TR></TBODY></TABLE>The circular buffer limits are the same as the 
range specified for the receive FIFO, however the address can be set outside of 
that range and will only be affected by the FIFO boundary if it crosses the FIFO 
end location by reading from the circular buffer.<BR><BR><B>05Ah - 
W_RXBUF_READCSR - Wifi RX Fifo Read or "start" cursor (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Address in RAM
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>This value is specified the same as 
W_RXBUF_WRCSR - it's purely software controlled so it's up to the programmer to 
move the start cursor after loading a packet. if W_RXBUF_READCSR != 
W_RXBUF_WRCSR, then one or more packets exist in the FIFO that need to be 
processed. (See the section on HW RX Headers, for information on calculating 
packet lengths) Once a packet has been processed, the software should advance 
the read cursor to the beginning of the next packet.<BR><BR><B>060h - 
W_RXBUF_RD_DATA - Wifi CircBuf Read Data (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Data
</PRE></TD></TR></TBODY></TABLE>returns the 16bit value at the address specified 
by W_RXBUF_RD_ADDR, and increments W_RXBUF_RD_ADDR by 2. If the increment causes 
W_RXBUF_RD_ADDR to equal the address specified in W_RXBUF_END, W_RXBUF_RD_ADDR 
will be reset to the address specified in W_RXBUF_BEGIN.<BR>Ports 1060h, 6060h, 
7060h are PASSIVE mirrors of 0060h, reading from these mirrors returns the old 
latched value from previous read from 0060h, but without reading a new value 
from RAM, and without incrementing the address.<BR><BR><B>062h - W_RXBUF_GAP - 
Wifi RX Gap Address (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Always zero
  1-12  Halfword Address in RAM
  13-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Seems to be intended to define a "gap" in the 
circular buffer, done like so:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr=Addr+2 and 1FFEh  ;address increment (by W_RXBUF_RD_DATA read)
  if Addr=RXBUF_END then ;normal begin/end wrapping (done before gap wraps)
     Addr=RXBUF_BEGIN
  if Addr=RXBUF_GAP then ;now gap-wrap (may include further begin/end wrap)
     Addr=RXBUF_GAP+RXBUF_GAPDISP*2
     if Addr&gt;=RXBUF_END then Addr=Addr+RXBUF_BEGIN-RXBUF_END  ;wrap more
</PRE></TD></TR></TBODY></TABLE>To disable the gap stuff, set both W_RXBUF_GAP 
and W_RXBUF_GAPDISP to zero.<BR><BR><B>064h - W_RXBUF_GAPDISP - Wifi RX Gap 
Displacement Offset (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Offset, used with W_RXBUF_GAP (see there)
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Caution: On the DS-Lite, after adding it to 
W_RXBUF_RD_ADDR, the W_RXBUF_GAPDISP setting is destroyed (reset to 0000h) by 
hardware. The original DS leaves W_RXBUF_GAPDISP intact.<BR><BR><B>05Ch - 
W_RXBUF_COUNT (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Decremented on reads from W_RXBUF_RD_DATA
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Triggers IRQ09 when it reaches zero, and does 
then stay at zero (without further decrementing, and without generating further 
IRQs).<BR>Note: Also decremented on (accidental) writes to read-only 
W_RXBUF_RD_DATA.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifireceivestatistics></A><FONT size=+2>&nbsp;DS Wifi 
      Receive Statistics</FONT></TD></TR></TBODY></TABLE><BR><B>1A8h - W_RXSTAT_INC_IF 
- Statistics Increment Flags (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12   Increment Flags (see Port 1B0h..1BFh)
  13-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Bitmask for which statistics have been increased 
at least once.<BR>Unknown how to reset/acknowledge these bits... possibly by 
reading from 1A8h, or by reading from 1B0h..1BFh, or eventually/obscurely by 
writing to 1ACh.<BR><BR><B>1AAh - W_RXSTAT_INC_IE - Statistics Increment 
Interrupt Enable (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12   Counter Increment Interrupt Enable (see Port 1B0h..1BFh) (1=Enable)
  13-15  Unknown (usually zero)
</PRE></TD></TR></TBODY></TABLE>Statistic Interrupt Enable Control register for 
Count Up.<BR>Note: ------&gt; seems to trigger IRQ02 ...?<BR><BR><B>1ACh - 
W_RXSTAT_OVF_IF - Statistics Half-Overflow Flags (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12   Half-Overflow Flags (see Port 1B0h..1BFh)
  13-15  Always zero
</PRE></TD></TR></TBODY></TABLE>The W_RXSTAT_OVF_IF bits are simply containing 
the current bit7-value of the corresponding counters, setting or clearing that 
counter bits is directly reflected to W_RXSTAT_OVF_IF.<BR>The recommended way to 
acknowledge W_RXSTAT_OVF_IF is to read the corresponding counters (which are 
reset to 00h after reading). For some reason, the firmware is additionally 
writing FFFFh to W_RXSTAT_OVF_IF (that is possibly a bug, or it does acknowlege 
something internally?).<BR><BR><B>1AEh - W_RXSTAT_OVF_IE - Statistics 
Half-Overflow Interrupt Enable (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12   Half-Overflow Interrupt Enable (see Port 1B0h..1BFh) (1=Enable)
  13-15  Unknown (usually zero)
</PRE></TD></TR></TBODY></TABLE>Statistic Interrupt Enable for Overflow, bits 
same as in W_RXSTAT_INC_IE<BR>Note: ------&gt; seems to trigger IRQ04 
...?<BR><BR><B>1B0h..1BFh - W_RXSTAT - Receive Statistics (R/W, except 1B5h: 
Read-only)</B><BR>W_RXSTAT is a collection of 8bit counters, which are 
incremented upon certain events. These entries are automatically reset to 0000h 
after reading. Should be accessed with LDRH opcodes (using LDRB to read only 
8bits does work, but the read is internally expanded to 16bit, and so, the whole 
16bit value will be reset to 0000h).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Port  Dir  Bit  Expl.
  1B0h  R/W  0    W_RXSTAT  ?
  1B1h  -    -    Always 0  -
  1B2h  R/W  1    W_RXSTAT  ?       "RX_LengthErrorCount or RX_RateErrorCount"
  1B3h  R/W  2    W_RXSTAT  Length&gt;2348 error
  1B4h  R/W  3    W_RXSTAT  RXBUF Full error
  1B5h  R    4?   W_RXSTAT  ?    (R) (but seems to exist; used by firmware)
  1B6h  R/W  5    W_RXSTAT  Length=0 Error                  ;"0x20=FCS_ERROR,"
  1B7h  R/W  6    W_RXSTAT  Packet Received Okay            ;"0x40=FCS_OK,"
                             (also increments on W_MACADDR mis-match)
                             (also increments on internal ACK packets)
                             (also increments on invalid IEEE type=3)
                             (also increments TOGETHER with 1BCh and 1BEh)
                             (not incremented on RXBUF_FULL error)
  1B8h  R/W  7    W_RXSTAT  ?
  1B9h  -    -    Always 0  -
  1BAh  R/W  8    W_RXSTAT  ?
  1BBh  -    -    Always 0  -
  1BCh  R/W  9    W_RXSTAT  WEP Error (when FC.Bit14 is set)
  1BDh  R/W  10   W_RXSTAT  ?
  1BEh  R/W  11   W_RXSTAT  (duplicated sequence control) ;"0x800 = DUPE, ?"
  1BFh  R/W  12   W_RXSTAT  ?
</PRE></TD></TR></TBODY></TABLE><BR><B>1C4h - W_RX_COUNT (W_INTERNAL) 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-?   Receive Okay Count (increments together with ports 1B4h + 1B7h)
  8-?   Receive Error Count (increments together with ports 1B3h + 1B6h)
</PRE></TD></TR></TBODY></TABLE>Increments when receiving a packet. 
Automatically reset to zero after reading.<BR><BR><B>1D0h..1DFh - W_STAT - 
Related to multiplayer response errors (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  1D0h        Not used (always zero)
  1D1h..1DFh  Client 1..15
</PRE></TD></TR></TBODY></TABLE>Incremented on errors (and/or on success?). 
Probably related to W_AID_LOW.<BR>Automatically reset to zero after reading. 
Responses should be somehow sent through Port 094h, don't know how/when/if that 
data is transferred, maybe automatically after receiving beacons...?<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifitransmitcontrol></A><FONT size=+2>&nbsp;DS Wifi Transmit 
      Control</FONT></TD></TR></TBODY></TABLE><BR><B>0ACh - W_TXREQ_RESET - Reset 
Transfer Request Bits (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Reset corresponding bits in W_TXREQ_READ (0=No change, 1=Reset)
  4-15  Unknown (if any)
</PRE></TD></TR></TBODY></TABLE>Firmware writes values 01h,02h,08h,0Dh, and 
FFFFh.<BR><BR><B>0AEh - W_TXREQ_SET - Set Transfer Request Bits (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Set corresponding bits in W_TXREQ_READ (0=No change, 1=Set)
  4-15  Unknown (if any)
</PRE></TD></TR></TBODY></TABLE>Firmware writes values 
01h,02h,05h,08h,0Dh.<BR><BR><B>0B0h - W_TXREQ_READ - Get Transfer Request Bits 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Send W_TXBUF_LOC1  (1=Transfer, if enabled in W_TXBUF_LOC1.Bit15)
  1     Send W_TXBUF_EXTRA (1=Transfer, if enabled in W_TXBUF_EXTRA.Bit15)
  2     Send W_TXBUF_LOC2  (1=Transfer, if enabled in W_TXBUF_LOC2.Bit15)
  3     Send W_TXBUF_LOC3  (1=Transfer, if enabled in W_TXBUF_LOC3.Bit15)
  4     Unknown (seems to be always 1) (never used by firmware part4)
  5-15  Unknown/Not used
</PRE></TD></TR></TBODY></TABLE>Bit0-3 can be set/reset via 
W_TXREQ_SET/W_TXREQ_RESET. The setting in W_TXREQ_READ remains intact even after 
the transfer(s) have completed.<BR>If more than one of the LOC1,2,3 bits is set, 
then LOC3 is transferred first, LOC1 last. Beacons are transferred in every 
Beacon Timeslot (if enabled in W_TXBUF_BEACON.Bit15).<BR>Bit0,2,3 are 
automatically reset upon IRQ14 (by hardware).<BR><BR><B>0B6h - W_TXBUSY 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     W_TXBUF_LOC1  (1=Requested Transfer busy, or not yet started at all)
  1     W_TXBUF_EXTRA (1=Requested Transfer busy, or not yet started at all)
  2     W_TXBUF_LOC2  (1=Requested Transfer busy, or not yet started at all)
  3     W_TXBUF_LOC3  (1=Requested Transfer busy, or not yet started at all)
  4     W_TXBUF_BEACON  (1=Beacon Transfer busy)
  5-15  Unknown (if any)
</PRE></TD></TR></TBODY></TABLE>Busy bits. If all three W_TXBUF_LOC's are sent, 
then it goes through values 0Dh,05h,01h,00h; ie. LOC3 is transferred first, LOC1 
last. The register is updated upon IRQ01 (by hardware).<BR>Bit4 is set only in 
Beacon Timeslots.<BR><BR><B>0B8h - W_TXSTAT - RESULT - Status of transmitted 
frame (R)</B><BR>For LOC1-3, this register is updated at the end of a transfer 
(upon the IRQ01 request), if retries occur then it is updated only after the 
final retry.<BR>For BEACON, this register is updated only if enabled in 
W_TXSTATCNT.Bit15, and only after successful transfers (since beacon errors 
result in infinite retries).<BR>For EXTRA, this register is updated only if 
enabled in W_TXSTATCNT.Bit13,14).<BR>Bit0/1 act similar to W_IF Bit1/3, however, 
the W_IF Bits are set after each transmit (including retries).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     One (or more) Packet has Completed (1=Yes)
        (No matter if successful, for that info see Bit1)
        (No matter if ALL packets are done, for that info see Bit12-13)
  1     Packet Failed (1=Error)
  2-7   Unknown/Not used
  8-11  Usually 0, ...but firmware is checking for values 03h,08h,0Bh
        (gets set to 07h when transferred W_TXBUF_LOC1/2/3 did have Bit12=set)
        (gets set to 00h otherwise)
        (gets set to 03h after beacons; if enabled in W_TXSTATCNT.Bit15)
        (gets set to 08h or 0Bh after EXTRA; depending on W_TXSTATCNT.Bit13,14)
  12-13 Packet which has updated W_TXSTAT (0=LOC1/BEACON/EXTRA, 1=LOC2, 2=LOC3)
  14-15 Unknown/Not used
</PRE></TD></TR></TBODY></TABLE>No idea how to reset bit0/1 once when they are 
set?<BR><BR><B>008h - W_TXSTATCNT (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-12  Unknown (usually zero)
  13    Update W_TXSTAT=0B01h and trigger IRQ01 after EXTRA transmits  (1=Yes)
  14    Update W_TXSTAT=0800h and trigger IRQ01 after EXTRA transmits  (1=Yes)
  15    Update W_TXSTAT and trigger IRQ01 after BEACON transmits (0=No, 1=Yes)
</PRE></TD></TR></TBODY></TABLE>If both Bit13 and Bit14 are set, then Bit13 is 
having priority.<BR>Note: LOC1..3 transmits are always updating W_TXSTAT and 
triggering IRQ01.<BR><BR><B>210h - W_TX_SEQNO - Transmit Sequence Number 
(R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11   Increments on IRQ07 (Transmit Start Interrupt)
  12-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Also incremented shortly after IRQ12.<BR>When 
enabled in W_TXBUF_LOCn.Bit13, this value replaces the upper 12bit of the IEEE 
Frame Header's Sequence Control value (otherwise, when disabled, the original 
value in Wifi RAM is used, and, in that case, W_TX_SEQNO is NOT 
incremented).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifitransmitbuffers></A><FONT size=+2>&nbsp;DS Wifi Transmit 
      Buffers</FONT></TD></TR></TBODY></TABLE><BR><B>068h - W_TXBUF_WR_ADDR - Wifi 
CircBuf Write Address (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Always zero
  1-12  Halfword Address in RAM for Writes via W_TXBUF_WR_DATA
  13-15 Always zero
</PRE></TD></TR></TBODY></TABLE><BR><B>070h - W_TXBUF_WR_DATA - Wifi CircBuf 
Write Data (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Data to be written to address specified in W_TXBUF_WR_ADDR
</PRE></TD></TR></TBODY></TABLE>After writing to this register, W_TXBUF_WR_ADDR 
is automatically incremented by 2, and, if it gets equal to W_TXBUF_GAP, then it 
gets additonally incremented by W_TXBUF_GAPDISP*2.<BR><BR><B>074h - W_TXBUF_GAP 
- Wifi CircBuf Write Top (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Always zero
  1-12  Halfword Address
  13-15 Always zero
</PRE></TD></TR></TBODY></TABLE><BR><B>076h - W_TXBUF_GAPDISP - Wifi CircBuf 
Write Offset from Top to Bottom (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Offset (added to; if equal to W_TXBUF_GAP)
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Should be "0-write_buffer_size" (wrap from end 
to begin), or zero (no wrapping).<BR>Caution: On the DS-Lite, after adding it to 
W_TXBUF_WR_ADDR, the W_TXBUF_GAPDISP setting is destroyed (reset to 0000h) by 
hardware. The original DS leaves W_TXBUF_GAPDISP intact.<BR><BR>Note: 
W_TXBUF_GAP and W_TXBUF_GAPDISP may be (not TOO probably) also used by transmits 
via W_TXBUF_LOCn and W_TXBUF_BEACON (not tested).<BR><BR><B>080h - 
W_TXBUF_BEACON - Beacon Transmit Location (R/W)</B><BR><B>090h - W_TXBUF_EXTRA - 
Extra Transmit Location (R/W)</B><BR><B>0A0h - W_TXBUF_LOC1 - Transmit location 
1 (R/W)</B><BR><B>0A4h - W_TXBUF_LOC2 - Transmit location 2 (R/W)</B><BR><B>0A8h 
- W_TXBUF_LOC3 - Transmit location 3 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Halfword Address of TX Frame Header in RAM
  12    For LOC1-3: When set, W_TXSTAT.bit8-10 are set to 07h after transfer
        For BEACON: Unknown, no effect on W_TXSTAT
        For EXTRA: Unknown, no effect on W_TXSTAT
  13    IEEE Sequence Control (0=From W_TX_SEQNO, 1=Value in Wifi RAM)
        For BEACON: Unknown (always uses W_TX_SEQNO) (no matter of bit13)
  14    Unknown
  15    Transfer Request (1=Request/Pending)
</PRE></TD></TR></TBODY></TABLE>For LOC1..3 and EXTRA, Bit15 is automatically 
cleared after transfer (no matter if the transfer was successful). For Beacons, 
bit15 is kept unchanged since beacons are intended to be transferred 
repeatedly.<BR>The purpose of W_TXBUF_EXTRA is unknown... maybe for automatic 
replies...? Pictochat seems to use it for host-to-client data frames. 
W_TXBUF_EXTRA.Bit15 can be set ONLY while W_EXTRACOUNT is 
non-zero.<BR><BR><B>0B4h - W_TXBUF_RESET (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Disable LOC1    (0=No change, 1=Reset W_TXBUF_LOC1.Bit15)
  1     Disable EXTRA   (0=No change, 1=Reset W_TXBUF_EXTRA.Bit15)
  2     Disable LOC2    (0=No change, 1=Reset W_TXBUF_LOC2.Bit15)
  3     Disable LOC3    (0=No change, 1=Reset W_TXBUF_LOC3.Bit15)
  4-5   Unknown/Not used
  6     Unknown         (used by firmware) (probably ack/reset Port 098h...?)
  7     Unknown         (0=No change, 1=Reset Port 094h.Bit15)
  8-15  Unknown/Not used
</PRE></TD></TR></TBODY></TABLE>Firmware writes values FFFFh, 40h, 02h, xxxx, 
09h, 01h, 02h, C0h.<BR><BR><B>084h - W_TXBUF_TIM - Beacon TIM Index in Frame 
Body (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Location of TIM parameters within Beacon Frame Body
  8-15  Not used/zero
</PRE></TD></TR></TBODY></TABLE>Usually set to 15h, that assuming that 
preceeding Frame Body content is: Timestamp(8), BeaconInterval(2), 
Capability(2), SuppRatesTagLenParams(4), ChannelTagLenParam(3), TimTagLen(2); so 
the value points to TimParams (ie. after TimTagLen).<BR><BR><B>06Ch - 
W_TXBUF_COUNT (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11  Decremented on writes to W_TXBUF_WR_DATA
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Triggers IRQ08 when it reaches zero, and does 
then stay at zero (without further decrementing, and without generating further 
IRQs).<BR>Note: Not affected by (accidental) reads from write-only 
W_TXBUF_WR_DATA.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifitransmiterrors></A><FONT size=+2>&nbsp;DS Wifi Transmit 
      Errors</FONT></TD></TR></TBODY></TABLE><BR><B>Automatic ACKs</B><BR>Transmit 
errors occur on missing ACKs. The NDS hardware is automatically responding with 
an ACK when receiving a packet (if it has been addressed to the receipients 
W_MACADDR setting). And, when sending a packet, the NDS hardware is 
automatically checking for ACK responses.<BR>The only exception are packets that 
are sent to group addresses (ie. Bit0 of the 48bit MAC address being set to "1", 
eg. Beacons sent to FF:FF:FF:FF:FF:FF), the receipient(s) don't need to respond 
to such packets, and the sender always passes okay without checking for 
ACKs.<BR><BR><B>02Ch - W_TX_RETRYLIMIT (R/W)</B><BR>Specifies the maximum number 
of retries on Transmit Errors (eg. 07h means one initial transmit, plus 7 
retries, ie. max 8 transmits in total).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Retry Count (usually 07h)
  8-15  Unknown     (usually 07h)
</PRE></TD></TR></TBODY></TABLE>The Retry Count value is decremented on each 
Error (unless it is already 00h). There's no automatic reload, so 
W_TX_RETRYLIMIT should be reinitialized by software prior to each transmit. When 
sending multiple packets (by setting more than one bit with W_TXREQ_SET), then 
the first packet may eat-up all retries, leaving only a single try to the other 
packet(s).<BR><BR><B>1C0h - W_TX_ERR_COUNT - TransmitErrorCount (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   TransmitErrorCount
  8-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Increments on Transmit Errors. Automatically 
reset to zero after reading.<BR>IRQ03 triggered when W_TX_ERR_COUNT is 
incremented (for NON-beacons ONLY).<BR>IRQ05 triggered when W_TX_ERR_COUNT &gt; 
7Fh (happens INCLUDING for beacons).<BR><BR><B>Error 
Notification</B><BR>Transmit Errors can be sensed via W_TX_ERR_COUNT, IRQ03, 
IRQ05, TX Hardware Header entry [00h], and 
W_TXSTAT.Bit1.<BR><BR><B>W_TXBUF_BEACON Errors</B><BR>As the name says, 
W_TXBUF_BEACON is intended for sending Beacons to group addresses (which do not 
require to respond by ACKs). So, transmit errors would occur only when mis-using 
W_TXBUF_BEACON to send packets to individual addresses, but the W_TXBUF_BEACON 
error handling isn't fully implemented:<BR>First of, W_TX_RETRYLIMIT isn't used, 
instead, W_TXBUF_BEACON errors will result in infinite retries.<BR>Moreover, 
W_TXBUF_BEACON errors seem to increment W_TX_ERR_COUNT, but without generating 
IRQ03, however, IRQ05 is generated when W_TX_ERR_COUNT&gt;7Fh.<BR><BR><B>Other 
Errors</B><BR>The NDS transmit hardware seems to do little error checking on the 
packet headers. The only known error-checked part is byte [04h] in the TX 
hardware header (which must be 00h, 01h, or 02h). Aside from that, when sent to 
a group address, it is passing okay even with invalid IEEE type/subtypes, and 
even with Length/Rate entries set to zero. However, when sending such data to an 
individual address, the receiving NDS won't respond by 
ACKs.<BR><BR><B>Note</B><BR>Received ACKs aren't stored in WifiRAM (or, 
possibly, they ARE stored, but without advancing W_RXBUF_WRCSR, so that the 
software won't see them, and so that they will be overwritten by the next 
packet).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifistatus></A><FONT size=+2>&nbsp;DS Wifi 
  Status</FONT></TD></TR></TBODY></TABLE><BR><B>19Ch - W_RF_PINS - Status of 
RF-Chip Control Signals (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0    Reportedly "carrier sense" (maybe 1 during RX.DTA?) (usually 0)
  1    TX.MAIN (RFU.Pin17) Transmit Data Phase          (0=No, 1=Active)
  2    Unknown (RFU.Pin3)  Seems to be always high      (Always 1=high?)
  3-5  Not used                                         (Always zero)
  6    TX.ON   (RFU.Pin14) Transmit Preamble+Data Phase (0=No, 1=Active)
  7    RX.ON   (RFU.Pin15) Receive Mode                 (0=No, 1=Enabled)
  8-15 Not used                                         (Always zero)
</PRE></TD></TR></TBODY></TABLE>Physical state of the RFU board's RX/TX pins. 
Similar to W_RF_STATUS.<BR><BR><B>214h - W_RF_STATUS - Current Transmit/Receive 
State (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3  Current Transmit/Receive State:
        0 = Initial Value on power-up (before raising W_MODE_RST.Bit0)
        1 = RX Mode enabled (waiting for incoming data)
        2 = Switching from RX to TX (takes a few clock cycles)
        3 = TX Mode active  (sending preamble and data)
        4 = Switching from TX to RX (takes a few clock cycles)
        5 = Unknown, firmware checks for that value (maybe RX busy)
        6 = Unknown, firmware checks for that value (maybe RX busy)
        9 = Idle (upon IRQ13, and upon raising W_MODE_RST.Bit0)
  4-15 Always zero?
</PRE></TD></TR></TBODY></TABLE>Numeric Status Code. Similar to 
W_RF_PINS.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifitimers></A><FONT size=+2>&nbsp;DS Wifi 
  Timers</FONT></TD></TR></TBODY></TABLE><BR><B>0E8h - W_US_COUNTCNT - Microsecond 
counter enable (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Counter Enable (0=Disable, 1=Enable)
  1-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Activates W_US_COUNT, and also W_BEACONCOUNT1 
and W_BEACONCOUNT2 (which are decremented when lower 10bit of W_US_COUNT wrap 
from 3FFh to 000h). Note: W_POWER_US must be enabled, too.<BR><BR><B>0F8h - 
W_US_COUNT0 - Microsecond counter, bits 0-15 (R/W)</B><BR><B>0FAh - W_US_COUNT1 
- Microsecond counter, bits 16-31 (R/W)</B><BR><B>0FCh - W_US_COUNT2 - 
Microsecond counter, bits 32-47 (R/W)</B><BR><B>0FEh - W_US_COUNT3 - Microsecond 
counter, bits 48-63 (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-63  Counter Value in microseconds (incrementing)
</PRE></TD></TR></TBODY></TABLE>Clocked by the 22.00MHz oscillator on the RFU 
board (ie. not by the 33.51MHz system clock). The 22.00MHz are divided by a 
22-step prescaler.<BR><BR><B>0EAh - W_US_COMPARECNT - Microsecond compare enable 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Compare Enable (0=Disable, 1=Enable) (IRQ14/IRQ15)
  1     Force IRQ14    (0=No, 1=Force Now)   (Write-only)
  2-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Activates IRQ14 on W_US_COMPARE matches, and 
IRQ14/IRQ15 on W_BEACONCOUNT1.<BR><BR><B>0F0h - W_US_COMPARE0 - Microsecond 
compare, bits 0-15 (R/W)</B><BR><B>0F2h - W_US_COMPARE1 - Microsecond compare, 
bits 16-31 (R/W)</B><BR><B>0F4h - W_US_COMPARE2 - Microsecond compare, bits 
32-47 (R/W)</B><BR><B>0F6h - W_US_COMPARE3 - Microsecond compare, bits 48-63 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Always zero... firmware writes 1 though (maybe write-only flag?)
  1-9   Always zero
  10-63 Compare Value in milliseconds (aka microseconds/1024)
</PRE></TD></TR></TBODY></TABLE>Triggers IRQ14 (see IRQ14 notes below) when 
W_US_COMPARE matches W_US_COUNT.<BR>Usually set to FFFFFFFFFFFFFC00h (ie. 
almost/practically never). Instead, IRQ14 is usually derived via 
W_BEACONCOUNT1.<BR><BR><B>11Ch - W_BEACONCOUNT1 (R/W)</B><BR>Triggers IRQ14 and 
IRQ15 (see IRQ14/IRQ15 notes below) when it reaches 0000h (if W_PRE_BEACON is 
non-zero, then IRQ15 occurs that many microseconds in advance).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Decrementing Millisecond Counter (reloaded with W_BEACONINT upon IRQ14)
</PRE></TD></TR></TBODY></TABLE>Set to W_BEACONINT upon IRQ14 events (unlike the 
other W_US_COMPARE related actions, this is done always, even if W_US_COMPARECNT 
is zero).<BR>When reaching 0000h, it is immediately reloaded (as for US_COUNT 
matches), so the counting sequence is ..,3,2,1,BEACONINT,.. (not 
3,2,1,ZERO,BEACONINT).<BR><BR><B>134h - W_BEACONCOUNT2 - Post-Beacon Counter 
(R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Decrementing Millisecond Counter (reloaded with FFFFh upon IRQ14)
</PRE></TD></TR></TBODY></TABLE>Triggers IRQ13 when it reaches 0000h (no matter 
of W_US_COMPARECNT), and does then stay fixed at 0000h (without any further 
decrement/wrapping to FFFFh).<BR>Set to FFFFh upon IRQ14 (by hardware), the 
IRQ14 handler should then adjust the register (by software) by adding the Tag 
DDh Beacon header's Stepping value (usually 000Ah) to it.<BR>Seems to be used to 
indicate beacon transmission time (possible including additional time being 
reserved for responses)?<BR><BR><B>08Ch - W_BEACONINT - Beacon Interval 
(R/W)</B><BR>Reload value for W_BEACONCOUNT1.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-9   Frequency in milliseconds of beacon transmission
  10-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Should be initialized randomly to 0CEh..0DEh or 
so. The random setting reduces risk of repeated overlaps with beacons from other 
hosts.<BR><BR><B>110h - W_PRE_BEACON - Pre-Beacon Time (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Pre-Beacon Time in microseconds (static value, ie. NOT decrementing)
</PRE></TD></TR></TBODY></TABLE>Allows to define the distance between IRQ15 and 
IRQ14. The setting doesn't affect the IRQ14 timing (which occurs at the 
W_BEACONCOUNT1'th millisecond boundary), but IRQ15 occurs in advance (at the 
W_BEACONCOUNT1'th millisecond boundary minus W_PRE_BEACON microseconds). If 
W_PRE_BEACON is zero, then both IRQ14 and IRQ15 occur exactly at the same 
time.<BR><BR><B>088h - W_LISTENCOUNT - Listen Count (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Decremented by hardware at IRQ14 events (ie. once every beacon)
  8-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Reload occurs immediately BEFORE decrement, ie. 
with W_LISTENINT=04h, it will go through values 
03h,02h,01h,00h,03h,02h,01h,00h,etc.<BR><BR><B>08Eh - W_LISTENINT - Listen 
Interval (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Listen Interval, counted in beacons (usually 02h)
  8-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Reload value for W_LISTENCOUNT.<BR><BR><B>10Ch - 
W_CONTENTFREE (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Decrementing microsecond counter
</PRE></TD></TR></TBODY></TABLE>Operated always (no matter of 
W_US_COUNTCNT).<BR>Once when it has reached 0000h, it seems to stay fixed at 
0000h.<BR>"[Set to the remaining duration of contention-free period 
when<BR>receiving beacons - only *really* necessary for powersaving 
mode]"<BR><BR><B>0EEh - W_EXTRACOUNTCNT (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Enable W_EXTRACOUNT (0=Disable, 1=Enable)
  1-15  Always Zero
</PRE></TD></TR></TBODY></TABLE><BR><B>118h - W_EXTRACOUNT (R/W) x ffff [0000] 
(used by firmware part4)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Decremented once every 10 microseconds (Stopped at 0000h)
</PRE></TD></TR></TBODY></TABLE>Unknown. Beacon / Timeslot related ?<BR>Written 
by firmware. Firmware IRQ14 handler checks for read value&lt;=0Ah.<BR>When it 
reaches zero, W_TXBUF_EXTRA is transferred (if enabled in W_TXBUF_EXTRA.Bit15, 
and in W_TXREQ_READ.Bit1), it does then trigger two (!) transfer start 
interrupts (IRQ07), transfer end is then indicated by a single IRQ12, optionally 
(when enabled in W_TXSTATCNT, IRQ01 (transfer done) is additionally generated 
(simultaneously with above IRQ12).<BR>NOPE, above isn't quite right..... when 
W_EXTRACOUNT is set to a very small value, then ONLY IRQ12 is triggered (so it 
might specify the duration during which the IRQ07's for W_TXBUF_EXTRA are 
allowed?)<BR><BR><B>IRQ13 Notes (Post-Beacon Interrupt)</B><BR>IRQ13 is 
generated by W_BEACONCOUNT2. It's simply doing:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_IF.Bit13=1      ;interrupt request
</PRE></TD></TR></TBODY></TABLE>If W_POWER_TX.Bit1=0, then additionally enter 
sleep mode:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_RF_PINS.Bit7=0  ;disable receive (enter idle mode) (RX.ON=Low)
  W_RF_STATUS=9     ;indicate idle mode
</PRE></TD></TR></TBODY></TABLE>Unlike for IRQ14/IRQ15, that's done no matter of 
W_US_COMPARECNT.<BR><BR><B>IRQ14 Notes (Beacon Interrupt)</B><BR>IRQ14 is 
generated by W_US_COMPARE, and by W_BEACONCOUNT1.<BR>Aside from just setting the 
IRQ flag in W_IF, the hardware does:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_BEACONCOUNT1=W_BEACONINT                             ;next IRQ15/IRQ14
  (Above is NOT done when IRQ14 was forced via W_US_COMPARECNT.Bit1)
</PRE></TD></TR></TBODY></TABLE>If W_US_COMPARECNT is 1, then the hardware does 
additionally:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  (Below IS ALSO DONE when IRQ14 was forced via W_US_COMPARECNT.Bit1)
  W_IF.Bit14=1
  W_BEACONCOUNT2=FFFFh ;about 64 secs (ie. almost never) ;next IRQ13 ("never")
  W_TXREQ_READ=W_TXREQ_READ AND FFF2h
  if W_TXBUF_BEACON.15 then W_TXBUSY.Bit4=1
  if W_LISTENCOUNT=00h then W_LISTENCOUNT=W_LISTENINT
  W_LISTENCOUNT=W_LISTENCOUNT-1
</PRE></TD></TR></TBODY></TABLE>If W_TXBUF_BEACON.Bit15=1, then following is 
done shortly after IRQ14:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_RF_PINS.Bit7=0  ;disable receive (RX.ON=Low)
  W_RF_STATUS=2     ;indicate switching from RX to TX mode
</PRE></TD></TR></TBODY></TABLE>If W_TXBUF_BEACON.Bit15=1, then following is 
done a bit later:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_RF_PINS.Bit6=1  ;transmit preamble start (TX.ON=High)
  W_RF_STATUS=3     ;indicate TX mode
</PRE></TD></TR></TBODY></TABLE>The IRQ14 handler should then do the following 
(by software):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_BEACONCOUNT2 = W_BEACONCOUNT2 + TagDDhSteppingValue  ;next IRQ13
</PRE></TD></TR></TBODY></TABLE>For using only ONE of the two IRQ14 sources: 
W_BEACONCOUNT1 can be disabled by setting both W_BEACONCOUNT1 and W_BEACONINT to 
zero. W_US_COMPARE can be sorts of "disabled" by setting it to value distant 
from W_US_COUNT, such like compare=count-400h.<BR><BR><B>IRQ07 Notes (Transmit 
Start Data; occurs after preamble)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_IF.Bit7=1       ;interrupt request
  W_RF_PINS.Bit1=1  ;start data transfer (preamble finished now) (TX.MAIN=High)
</PRE></TD></TR></TBODY></TABLE>Below only if packet was sent through 
W_TXBUF_BEACON, or if it was sent via W_TXBUF_LOCn, with W_TXBUF_LOCn.Bit13 
being zero:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [TXBUF...] = W_TX_SEQNO*10h   ;auto-adjust IEEE Sequence Control
  W_TX_SEQNO=W_TX_SEQNO+1       ;increase sequence number
</PRE></TD></TR></TBODY></TABLE><BR><B>IRQ01 Notes (Transmit Done)</B><BR>The 
following happens shortly before IRQ01:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_RF_PINS.Bit6=0  ;disable TX (TX.ON=Low)
  W_RF_STATUS=4     ;indicate switching from TX to RX mode
</PRE></TD></TR></TBODY></TABLE>Then, upon IRQ01, the following happens:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_IF.Bit1=1       ;interrupt request
  W_RF_PINS.Bit1=0  ;disable TX (TX.MAIN=Low)
  W_RF_PINS.Bit7=1  ;enable RX (RX.ON=High)
  W_RF_STATUS=1     ;indicate RX mode
</PRE></TD></TR></TBODY></TABLE><BR><B>IRQ15 Notes (Pre-Beacon 
Interrupt)</B><BR>IRQ15 is generated via W_BEACONCOUNT1 and W_PRE_BEACON. It's 
simply doing:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  if W_US_COMPARECNT=1 then W_IF.Bit15=1
</PRE></TD></TR></TBODY></TABLE>If W_POWER_TX.Bit0=1, then additionally wakeup 
from sleep mode:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_RF_PINS.Bit7=1  ;enable RX (RX.ON=High) ;\gets set like so a good while
  W_RF_STATUS=1     ;indicate RX mode       ;/after IRQ15 (but not immediately)
</PRE></TD></TR></TBODY></TABLE><BR><B>Beacon IRQ Sequence</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  IRQ15  Pre-Beacon  (beacon will be transferred soon)
  IRQ14  Beacon      (beacon will be transferred very soon) (carrier starts)
  IRQ07  Tx Start    (beacon transfer starts) (if enabled in W_TXBUF_BEACON.15)
  IRQ01  Tx End      (beacon transfer done) (if enabled in W_TXSTATCNT.15)
  IRQ13  Post-Beacon (beacon transferred) (unless next IRQ14 occurs earlier)
</PRE></TD></TR></TBODY></TABLE>That, for tranmitting beacons. (For receiving, 
IRQ07/IRQ01 would be replaced by Rx IRQ's, provided that a remote unit is 
sending beacons).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswificonfigurationports></A><FONT size=+2>&nbsp;DS Wifi 
      Configuration Ports</FONT></TD></TR></TBODY></TABLE><BR><B>120h - W_CONFIG_120h 
(R/W) ;81ff 0048-&gt;SAME ...init from firmware[04Ch]</B><BR><B>122h - 
W_CONFIG_122h (R/W) ;ffff 4840-&gt;SAME ...init from 
firmware[04Eh]</B><BR><B>124h - W_CONFIG_124h (R/W) ;ffff 0000-&gt;0032 ...init 
from firmware[05Eh]</B><BR><B>128h - W_CONFIG_128h (R/W) ;ffff 0000-&gt;01F4 
...init from firmware[060h]</B><BR><B>130h - W_CONFIG_130h (R/W) ;0fff 
0142-&gt;0140 ...init from firmware[054h]</B><BR><B>132h - W_CONFIG_132h (R/W) 
;8fff 8064-&gt;SAME ...init from firmware[056h]</B><BR><B>140h - W_CONFIG_140h 
(R/W) ;ffff 0000-&gt;E0E0 ...init from firmware[058h]</B><BR><B>142h - 
W_CONFIG_142h (R/W) ;ffff 2443-&gt;SAME ...init from 
firmware[05Ah]</B><BR><B>144h - W_CONFIG_144h (R/W) ;00ff 0042-&gt;SAME ...init 
from firmware[052h]</B><BR><B>146h - W_CONFIG_146h (R/W) ;00ff 0016-&gt;0002 
...init from firmware[044h]</B><BR><B>148h - W_CONFIG_148h (R/W) ;00ff 
0016-&gt;0017 ...init from firmware[046h]</B><BR><B>14Ah - W_CONFIG_14Ah (R/W) 
;00ff 0016-&gt;0026 ...init from firmware[048h]</B><BR><B>14Ch - W_CONFIG_14Ch 
(R/W) ;ffff 162C-&gt;1818 ...init from firmware[04Ah]</B><BR><B>150h - 
W_CONFIG_150h (R/W) ;ff3f 0204-&gt;0101 ...init from 
firmware[062h]</B><BR><B>154h - W_CONFIG_154h (R/W) ;7a7f 0058-&gt;SAME ...init 
from firmware[050h]</B><BR>These ports are to be initialized from firmware 
settings.<BR>Above comments show the R/W bits (eg. 81FFh means bit15 and bit8-0 
are R/W, bit14-9 are always zero), followed by the initial value on Reset (eg. 
0048h), followed by new value after initialization from firmware settings (eg. 
0032h, or SAME if the Firmware value is equal to the Reset value), followed by 
the location in firmware where the new value comes from (these values seem to be 
identical in all currently existing consoles).<BR>Note: Firmware part4 changes 
W_CONFIG_124h to C8h, and W_CONFIG_128h to 7D0h, and W_CONFIG_150h to 202h, and 
W_CONFIG_140h depending on tx rate and preamble:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  W_CONFIG_140h = firmware[058h]+0202h             ;1Mbit/s
  W_CONFIG_140h = firmware[058h]+0202h-6161h       ;2Mbit/s with long preamble
  W_CONFIG_140h = firmware[058h]+0202h-6161h-6060h ;2Mbit/s with short preamble
</PRE></TD></TR></TBODY></TABLE><BR><B>0ECh - W_CONFIG_0ECh (R/W) ;firmware 
writes 3F03h (same as on power-up)</B><BR><B>0D4h - W_CONFIG_0D4h (R/W) 
;firmware writes 0003h (affected by W_MODE_RST)</B><BR><B>0D8h - W_CONFIG_0D8h 
(R/W) ;firmware writes 0004h (same as on power-up)</B><BR><B>0DAh - 
W_CONFIG_0DAh (R/W) ;firmware writes 0602h (same as on power-up)</B><BR><B>254h 
- W_CONFIG_254h (?) ;firmware writes 0000h (read: EEEEh on 
DS-Lite)</B><BR>Firmware just initializes these ports with fixed values, without 
further using them after initialization.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifibasebandchipbb></A><FONT size=+2>&nbsp;DS Wifi Baseband 
      Chip (BB)</FONT></TD></TR></TBODY></TABLE><BR>BB-Chip Mitsumi MM3155 (DS), or 
BB/RF-Chip Mitsumi MM3218 (DS-Lite)<BR><BR><B>158h - W_BB_CNT - Baseband serial 
transfer control (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Index     (00h-68h)
  8-11  Not used  (should be zero)
  12-15 Direction (5=Write BB_WRITE to Chip, 6=Read from Chip to BB_READ)
</PRE></TD></TR></TBODY></TABLE>Transfer is started after writing to this 
register.<BR><BR><B>15Ah - W_BB_WRITE - Baseband serial write data (W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Data to be sent to chip (by following W_BB_CNT transfer)
  8-15  Not used (should be zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>15Ch - W_BB_READ - Baseband serial read 
data (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Data received from chip (from previous W_BB_CNT transfer)
  8-15  Not used (always zero)
</PRE></TD></TR></TBODY></TABLE><BR><B>15Eh - W_BB_BUSY - Baseband serial busy 
flag (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Transfer Busy (0=Ready, 1=Busy)
  1-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Used to sense transfer completion after writes 
to W_BB_CNT.<BR>Not sure if I am doing something wrong... but the busy flag 
doesn't seem to get set immediately after W_BB_CNT writes, and works only after 
waiting a good number of clock cycles?<BR><BR><B>160h - W_BB_MODE (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Always zero
  8     Unknown (usually 1) (no effect no matter what setting?)
  9-13  Always zero
  14    Unknown (usually 0) (W_BB_READ gets unstable when set)
  15    Always zero
</PRE></TD></TR></TBODY></TABLE>This register is initialized by firmware 
bootcode - don't change.<BR><BR><B>168h - W_BB_POWER (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Disable whatever   (usually 0Dh=disable)
  4-14  Always zero
  15    Disable W_BB_ports (usually 1=Disable)
</PRE></TD></TR></TBODY></TABLE>Must be set to 0000h before accessing BB 
registers.<BR><BR><B>Read-Write-Ability of the BB registers</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Index    Num Dir Expl.
  00h        1 R   always 6Dh (R) (Chip ID)
  01h..0Ch  12 R/W 8bit R/W
  0Dh..12h   6 -   always 00h
  13h..15h   3 R/W 8bit R/W
  16h..1Ah   5 -   always 00h
  1Bh..26h  12 R/W 8bit R/W
  27h        1 -   always 00h
  28h..4Ch     R/W 8bit R/W
  4Dh        1 R   always 00h or BFh (depending on other regs)
  4Eh..5Ch     R/W 8bit R/W
  5Dh        1 R   always 01h (R)
  5Eh..61h     -   always 00h
  62h..63h   2 R/W 8bit R/W
  64h        1 R   always FFh or 3Fh (depending on other regs)
  65h        1 R/W 8bit R/W
  66h        1 -   always 00h
  67h..68h   2 R/W 8bit R/W
  69h..FFh     -   always 00h
</PRE></TD></TR></TBODY></TABLE><BR><B>Important BB Registers</B><BR>Registers 
0..68h are initialized by firmware bootcode, and (most) of these settings do not 
need to be changed by other programs, except for:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Initial Meaning
  01h 0x9E    [unsetting/resetting bit 7 initializes/resets the system?]
  13h 0x00    CCA operation - criteria for receiving
                    0=only use Carrier Sense (CS)
                    1=only use Energy Detection (ED)
                    2=receive if CS OR ED
                    3=receive only if CS AND ED
  1Eh 0xBB    see change channels flowchart
  35h 0x1F    Energy Detection (ED) criteria
              value 0..61 (representing energy levels of -60dBm to -80dBm)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifirfchip></A><FONT size=+2>&nbsp;DS Wifi RF 
  Chip</FONT></TD></TR></TBODY></TABLE><BR>RF-Chip RF9008 (manufacturer?) (DS), or 
BB/RF-Chip Mitsumi MM3218 (DS-Lite)<BR><BR><B>17Ch - W_RF_DATA2 - RF chip serial 
data/transfer enable (R/W)</B><BR>For Type2 (ie. firmware[040h]&lt;&gt;3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Upper 2bit of 18bit data
  2-5   Index (00h..0Bh)
  6-7   Should be zero (part of 24bit transfer)
  8-15  Should be zero (not used with 24bit transfer)
</PRE></TD></TR></TBODY></TABLE>For Type3 (ie. firmware[040h]=3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-3   Command (should be 5=write data)
  4-15  Should be zero (not used with 20bit transfer)
</PRE></TD></TR></TBODY></TABLE>Writing to this register starts the 
transfer.<BR><BR><B>17Eh - W_RF_DATA1 - RF chip serial data (R/W)</B><BR>For 
Type2 (ie. firmware[040h]&lt;&gt;3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Lower 16bit of 18bit data
</PRE></TD></TR></TBODY></TABLE>For Type3 (ie. firmware[040h]=3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-7   Data
  8-15  Index (usually 00h..28h)
</PRE></TD></TR></TBODY></TABLE>This value should be set before setting 
W_RF_DATA2.<BR><BR><B>180h - W_RF_BUSY - RF chip serial busy flag (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Transfer Busy (0=Ready, 1=Busy)
  1-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Used to sense transfer completion after writes 
to W_RF_DATA2.<BR><BR><B>184h - W_RF_CNT - RF chip serial control (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-5   Transfer length (init from firmware[041h].Bit0-5)
  6-7   Always zero
  8     Unknown         (init from firmware[041h].Bit7)
  9-13  Always zero
  14    Unknown         (usually 0)
  15    Always zero
</PRE></TD></TR></TBODY></TABLE>This register is initialized by firmware 
bootcode - don't change.<BR>Usually, Type2 has length=24bit and flag=0. Type3 
uses length=20bit and flag=1.<BR><BR>RF chip data (Type2) (initial settings from 
firmware, example)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Firmware   Index   Data
  (24bit)    (4bit)  (18bit)
  00C007h  =  00h  + 0C007h ;-also set to 0C008h for power-down?
  129C03h  =  04h  + 29C03h
  141728h  =  05h  + 01728h ;\these are also written when changing channels
  1AE8BAh  =  06h  + 2E8BAh ;/
  1D456Fh  =  07h  + 1456Fh
  23FFFAh  =  08h  + 3FFFAh
  241D30h  =  09h  + 01D30h ;-bit10..14 should be also changed per channel?
  280001h  =  0Ah  + 00001h
  2C0000h  =  0Bh  + 00000h
  069C03h  =  01h  + 29C03h
  080022h  =  02h  + 00022h
  0DFF6Fh  =  03h  + 1FF6Fh
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiunknownregisters></A><FONT size=+2>&nbsp;DS Wifi Unknown 
      Registers</FONT></TD></TR></TBODY></TABLE><BR><B>268h - W_RXUNITS (R)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-11   Halfword address
  12-15  Always zero
</PRE></TD></TR></TBODY></TABLE>"Contains the number of HWORDs written to MAC 
mem since the start of the packet (this + W_RXBUF_WRCSR = next empty word in MAC 
mem) (used by firmware part4)."<BR>Note: Looks more like a full address (without 
the +W_RXBUF_WRCSR offset).<BR>Note: Seems to be used for both RX and 
TX.<BR><BR><B>094h (R/W) ffff [0000] ? (used by firmware part4)</B><BR>Seems to 
contain a RXBUF or TXBUF address, with a flag in bit15.<BR>1) [Firmware takes 
the value from Port 098h, and writes it to Port 094h, and then writes "1" to 
W_RXCNT.Bit7 (which is probably an instant transfer request), and does then 
restore the old Port 094h setting]<BR>2) [Firmware also uses this register to 
send client-to-host responses, that without using W_RXCNT.Bit7, so there must be 
another kind of "transfer request" in this case, possibly it get's transferred 
automatically shortly after receiving data or beacons or so from the 
host]<BR><BR><B>098h (R) 0000 [0000] (used by firmware part4) (IRQ06 among 
others)</B><BR>Seems to contain a RXBUF or TXBUF address, with a flag in 
bit15.<BR>Since it's read-only, it might be rather RXBUF than TXBUF 
related.<BR>However, it seems to be always 0000h (during and after both TX and 
RX).<BR>[Looking at how it is used in conjunction with Port 094h, this register 
seems to contain the address of a received packet which is to be forwarded to 
another station, ie. that't be in situations where two of the destination 
address fields in the IEEE header aren't equal to each other.] [Alternately, it 
may hold TX location after transmit errors, for retry/transmit 
purposes?].<BR><BR>---<BR><BR><B>00Ah - W_X_00Ah (R/W)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-15  Unknown (usually zero)
</PRE></TD></TR></TBODY></TABLE>"[bit7 - ingore rx duplicates]" &lt;--- that is 
NOT correct (no effect).<BR>Firmware writes 0000h to it. That, done many times. 
So, eventually some bits in these register are automatically set by hardware in 
whatever situations, otherwise repeatedly writing 0000h to it would be kinda 
useless...?<BR><BR><B>0C0h R/W x ffff [0000] (used by firmware part4) 
(Duration/ID...?)</B><BR><B>0C4h R/W x ffff [0000] (used by firmware 
part4)</B><BR>Unknown. Firmware writes something to them. The two registers are 
used in combination.<BR><BR><B>194h R/W x ---7 [0000]</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-2   Unknown. Firmware writes values 00h, 06h.
  3-15  Always zero
</PRE></TD></TR></TBODY></TABLE><BR><B>1A0h R/W x -933 [0000]</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Unknown
  2-3   Always zero
  4-5   Unknown
  6-7   Always zero
  8     Unknown
  9-10  Always zero
  11    Unknown
  12-15 Always zero
</PRE></TD></TR></TBODY></TABLE>Firmware writes values 000h, 823h. Seems to be 
power-related. The following experimental code toggles RXTX.ON (RFU.Pin4): "x=0 
/ @@lop: / [1A0h]=x / [036h]=0 / x=x XOR 3 / wait_by_loop(1000h) / b 
@@lop".<BR>Also, writing to port 1A0h affects ports 034h, 19Ch, 21Ch, and 
2A2h.<BR><BR><B>1A2h R/W x ---3 [0001] (used by firmware part4)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0-1   Unknown. Firmware writes values 03h, 01h, and VAR.
  2-15  Always zero
</PRE></TD></TR></TBODY></TABLE>Used in combination with Port 1A0h, so it's 
probably power-related, too.<BR><BR><B>1A4h R/W x ffff [0000]</B><BR>"Rate used 
when signal test is enabled (0x0A or 0x14 for 1 or 2 mbit)"<BR>(Not too sure if 
that's correct, there is no visible relation to any rate.)<BR>(This register 
seems to be R/W only on certain port 1A0h settings.)<BR>Unknown. Firmware writes 
whatever.<BR><BR><B>244h R/W x ffff [0000] (used by firmware 
part4)</B><BR>Unknown. Seems to be W_IF/W_IE related. Firmware sets Port 244h 
bits 6,7,12 to 1-then-0 upon IRQ06,IRQ07,IRQ12 respectively.<BR><BR><B>228h W x 
fixx [0000] (used by firmware part4) (bit3)</B><BR>Unknown. Firmware writes 
8-then-0 (done in IRQ06 handler, after Port 244h access).<BR><BR><B>290h (R/W or 
Disabled)</B><BR>Reportedly, this is the "antenna" register, which should exist 
on official devkits, allowing to switch between wired Ethernet, and wireless 
Wifi mode.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Unknown (R/W) (if present)
  1-15  Not used
</PRE></TD></TR></TBODY></TABLE>On normal NDS release versions, this register 
seems to be disabled (if it is implemented at all), and trying to read from it 
acts as for unused registers, ie. reads return FFFFh (or probably 0000h on 
NDS-lite). The NDS firmware contains code for accessing this port, even in 
release versions.<BR><BR><B>W_INTERNAL</B><BR>All registers marked as 
"W_INTERNAL" aren't used by Firmware part4, and are probably unimportant, except 
for whatever special diagnostics purposes.<BR><BR><B>Wifi DMA</B><BR>Wifi RAM 
can be accessed with normal "Start Immediately" DMA transfers (typically by 
reading through W_RXBUF_RD_DATA, so the DMA automatically wraps from END to 
BEGIN).<BR>Additionally, DMA0 and DMA2 can be reportedly synchronized to 
"Wireless Interrupt" (rather than using "Start Immediately" timing), no idea 
if/how that's working though... and if it gets started on any Wifi IRQ, or only 
on specific IRQs...?<BR>Possibly some of the above unknown registers, or some 
unknown bits in other registers, are DMA related...?<BR>Reportedly, early 
firmwares (v1 and/or v2) did use "Wireless Interrupt" DMAs.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiunusedregisters></A><FONT size=+2>&nbsp;DS Wifi Unused 
      Registers</FONT></TD></TR></TBODY></TABLE><BR><B>Wifi WS0 and WS1 Regions in 
NDS7 I/O Space</B><BR>Wifi hardware occupies two 32K slots, but most of it is 
filled with unused or duplicated regions. The timings (waitstates) for WS0 and 
WS1 are initialized in WIFIWAITCNT (by firmware).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  4800000h-4807FFFh Wifi WS0 Region (32K)
  4808000h-4808000h Wifi WS1 Region (32K)
  4810000h-4FFFFFFh Not used (00h-filled)
</PRE></TD></TR></TBODY></TABLE>Structure of the 32K Wifi Regions (WS0 and 
WS1)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Wifi-WS0-Region    Wifi-WS1-Region    Content
  4800000h-4800FFFh  4808000h-4808FFFh  Registers
  4801000h-4801FFFh  4809000h-4809FFFh  Registers (mirror)
  4802000h-4803FFFh  480A000h-480BFFFh  Unused
  4804000h-4805FFFh  480C000h-480DFFFh  Wifi RAM  (8K)
  4806000h-4806FFFh  480E000h-480EFFFh  Registers (mirror)
  4807000h-4807FFFh  480F000h-480FFFFh  Registers (mirror)
</PRE></TD></TR></TBODY></TABLE>Wifi Registers (recommended 4808000h-4808FFFh) 
appear more stable in WS1?<BR>Wifi RAM (recommended 4804000h-4805FFFh) appears 
more stable in WS0?<BR><BR><B>Unused Ports (Original NDS)</B><BR>Aside from 
those ports listed in the Wifi I/O Map, all other ports in range 000h..FFFh are 
unused. On the original DS, reading from these ports returns 
FFFFh.<BR><BR><B>Unused Ports (NDS-Lite)</B><BR>Reading from unused I/O ports 
acts as PASSIVE mirror of W_RXBUF_RD_DATA. Exceptions are: Ports 188h, and 
2D8h..2E6h; which always return 0000h.<BR><BR><B>Unused Memory (Original 
NDS)</B><BR>Unused Wifi Memory is at 2000h..3FFFh. On the original DS, reading 
from that region returns FFFFh.<BR><BR><B>Unused Memory 
(NDS-Lite)</B><BR>Reading from unused memory acts as PASSIVE mirror of WifiRAM 
(ie. reading from it returns the value being most recently read from 
4000h..5FFFh) (that not affected by indirect WifiRAM reads via W_RXBUF_RD_DATA) 
(and, that not affected by writes to wifi memory, including writes that do 
overwrite the most recent read value) (and, that only if WifiRAM is properly 
enabled, ie. Port 220h.Bits0-1 should be 0).<BR>Moreover, certain addresses are 
additionally ORed with mirrored I/O Ports. That addresses are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  2030h, 2044h, 2056h, 2080h, 2090h, 2094h, 2098h, 209Ch, 20A0h, 20A4h,
  20A8h, 20AAh, 20B0h, 20B6h, 20BAh, 21C0h, 2208h, 2210h, 2244h, 31D0h,
  31D2h, 31D4h, 31D6h, 31D8h, 31DAh, 31DCh, 31DEh.
</PRE></TD></TR></TBODY></TABLE>For example, 2044h is a PASSIVE mirror of 
WifiRAM, ORed with an ACTIVE mirror of W_RANDOM (Port 044h). Note that some 
mirrors are at 2000h-2FFFh, and some at 3000h-3FFFh. The W_STAT_xxx mirrors are 
PASSIVE (that, in unused memory region only) (in normal port-mirror regions like 
1000h-1FFF, W_STAT_xxx mirrors are ACTIVE).<BR><BR><B>Known (W) Mirrors (when 
reading from Write-only ports)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Read from (W)           Mirrors to (DS)        Or to (DS-Lite)
  070h W_TXBUF_WR_DATA    060h W_RXBUF_RD_DATA   074h W_TXBUF_GAP
  078h W_INTERNAL         068h W_TXBUF_WR_ADDR   074h W_TXBUF_GAP
  0ACh W_TXREQ_RESET      09Ch W_INTERNAL        ? (zero)
  0AEh W_TXREQ_SET        09Ch W_INTERNAL        ? (zero)
  0B4h W_TXBUF_RESET      0B6h W_TXBUSY          ? (zero)
  158h W_BB_CNT           15Ch W_BB_READ         ? (zero)
  15Ah W_BB_WRITE         ? (zero)               ? (zero)
  178h W_INTERNAL         17Ch W_RF_DATA2        ? (zero)
  20Ch W_INTERNAL         09Ch W_INTERNAL        ? (zero)
  21Ch W_IF_SET           010h W_IF              010h-OR-05Ch-OR-more?
  228h  x                 ? (zero)               ? (zero)
  298h W_INTERNAL         084h W_TXBUF_TIM       084h W_TXBUF_TIM
  2A8h W_INTERNAL         238h W_INTERNAL        238h W_INTERNAL
  2B0h W_INTERNAL         084h W_TXBUF_TIM       084h W_TXBUF_TIM
</PRE></TD></TR></TBODY></TABLE>Notes: The mirror to W_RXBUF_RD_DATA is a 
passive mirror.<BR>The DS-Lite mirror at 21Ch consists of several ports ORed 
with each other (known components are Ports 010h and 05Ch, but there seem to be 
even more values ORed with it).<BR><BR><B>Port Mirror Regions</B><BR>The Wifi 
Port region at 000h..FFFh is mirrored to 1000h..1FFFh, 6000h..6FFFh, and 
7000h..7FFFh. Many of that mirrored ports are PASSIVE mirrors. Eg. reading from 
1060h (mirror of Port 060h, W_RXBUF_RD_DATA) returns the old W_RXBUF_RD_DATA 
values (but without loading a new value from Wifi RAM, and without incrementing 
W_RXBUF_RD_ADDR). However, other registers, like W_RANDOM do have ACTIVE 
mirrors.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiinitialization></A><FONT size=+2>&nbsp;DS Wifi 
      Initialization</FONT></TD></TR></TBODY></TABLE><BR><B>Initialization 
sequence</B><BR>These events must be done somewhat in sequence. There is some 
flexibility as to how they can be ordered but it's best to follow this 
order:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  [4000304h].Bit1 = 1 ;POWCNT2  ;-Enable power to the wifi system
  W_MACADDR = firmware[036h]    ;-Set 48bit Mac address
  reg[012h] = 0000h   ;W_IE     ;-Disable interrupts
</PRE></TD></TR></TBODY></TABLE>Wake Up the wireless system:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[036h] = 0000h ;W_POWER_US ;\clear all powerdown bits
  delay 8 ms                    ; (works without that killer-delay ?)
  reg[168h] = 0000h ;W_BB_POWER ;/
  temp=BB[01h]                  ;\
  BB[01h]=temp AND 7Fh          ; reset BB[01h].Bit7, then restore old BB[01h]
  BB[01h]=temp                  ;/
  delay 30 ms                   ;-(more killer-delay now getting REALLY slow)
  call init_sub_functions       ;- same as "Init 16 registers by firmware[..]"
                                ;  and "Init RF registers", below.
                                ;  this or the other one probably not necessary
</PRE></TD></TR></TBODY></TABLE>Init the Mac system:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[004h] = 0000h   - W_MODE_RST       ;set hardware mode
  reg[008h] = 0000h   - W_TXSTATCNT      ;
  reg[00Ah] = 0000h   - ? W_X_00Ah       ;(related to rx filter)
  reg[012h] = 0000h   - W_IE             ;disable interrupts (again)
  reg[010h] = FFFFh   - W_IF             ;acknowledge/clear any interrupts
  reg[254h] = 0000h   - W_CONFIG_254h    ;
  reg[0B4h] = FFFFh   - W_TXBUF_RESET    ;--reset TXBUF_LOC's
                                         ;  so, why does it still work???
  reg[080h] = 0000h   - W_TXBUF_BEACON   ;disable automatic beacon transmission
  reg[02Ah] = 0000h   - W_AID_FULL       ;\clear AID
  reg[028h] = 0000h   - W_AID_LOW        ;/
  reg[0E8h] = 0000h   - W_US_COUNTCNT    ;disable microsecond counter
  reg[0EAh] = 0000h   - W_US_COMPARECNT  ;disable microsecond compare
  reg[0EEh] = 0001h   - W_EXTRACOUNTCNT  ;(not by firmware) (set reset anyways)
  reg[0ECh] = 3F03h   - W_CONFIG_0ECh    ;
  reg[1A2h] = 0001h   - ?                ;
  reg[1A0h] = 0000h   - ?                ;
  reg[110h] = 0800h   - W_PRE_BEACON     ;(firmware doesn't do that?)
  reg[0BCh] = 0001h   - W_PREAMBLE       ;disable short preamble
  reg[0D4h] = 0003h   - W_CONFIG_0D4h    ;
  reg[0D8h] = 0004h   - W_CONFIG_0D8h    ;
  reg[0DAh] = 0602h   - W_CONFIG_0DAh    ;
  reg[076h] = 0000h   - W_TXBUF_GAPDISP  ;disable gap/skip (offset=zero)
</PRE></TD></TR></TBODY></TABLE>Init 16 registers by firmware[044h..063h]<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[146h] = firmware[044h] ;W_CONFIG_146h
  reg[148h] = firmware[046h] ;W_CONFIG_148h
  reg[14Ah] = firmware[048h] ;W_CONFIG_14Ah
  reg[14Ch] = firmware[04Ah] ;W_CONFIG_14Ch
  reg[120h] = firmware[04Ch] ;W_CONFIG_120h
  reg[122h] = firmware[04Eh] ;W_CONFIG_122h
  reg[154h] = firmware[050h] ;W_CONFIG_154h
  reg[144h] = firmware[052h] ;W_CONFIG_144h
  reg[130h] = firmware[054h] ;W_CONFIG_130h
  reg[132h] = firmware[056h] ;W_CONFIG_132h
  reg[140h] = firmware[058h] ;W_CONFIG_140h
  reg[142h] = firmware[05Ah] ;W_CONFIG_142h
  reg[038h] = firmware[05Ch] ;W_POWER_TX
  reg[124h] = firmware[05Eh] ;W_CONFIG_124h
  reg[128h] = firmware[060h] ;W_CONFIG_128h
  reg[150h] = firmware[062h] ;W_CONFIG_150h
</PRE></TD></TR></TBODY></TABLE>Init RF registers<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  numbits = BYTE firmware[041h]    ;usually 18h
  numbytes = (numbits+7)/8         ;usually 3
  reg[0x184] = (numbits+80h) AND 017Fh  -- W_RF_CNT
  for i=0 to BYTE firmware[042h]-1 ;number of entries (usually 0Ch) (0..0Bh)
   if BYTE firmware[040h]=3
    RF[i]=firmware[0CEh+i]
   else
    RF_Write(numbytes at firmware[0CEh+i*numbytes])
   endif
</PRE></TD></TR></TBODY></TABLE>Init the BaseBand System<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  (this should be not required, already set by firmware bootcode)
  reg[160h] = 0100h  ;W_BB_MODE
  BB[0..68h] = firmware[64h+(0..68h)]
</PRE></TD></TR></TBODY></TABLE>Set Mac address<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  copy 6 bytes from firmware[036h] to mac address at 0x04800018  (why again ?)
</PRE></TD></TR></TBODY></TABLE>Now just set some default varibles<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[02Ch]=0007h  ;W_TX_RETRYLIMIT - XXX needs to be set for every transmit?
  Set channel (see section on changing channels)
  Set Mode 2 -- sets bottom 3 bits of W_MODE_WEP to 2
  Set Wep Mode / key -- Wep mode is bits 3..5 of W_MODE_WEP
  BB[13h] = 00h  ;CCA operation (use only carrier sense, without ED)
  BB[35h] = 1Fh  ;Energy Detection Threshold (ED)
</PRE></TD></TR></TBODY></TABLE>-- To further init wifi to the point that you 
can properly send<BR>-- and receive data, there are some more variables that 
need to be set.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[032h] = 8000h -- W_WEP_CNT     ;Enable WEP processing
  reg[134h] = FFFFh -- W_BEACONCOUNT2;reset post-beacon counter to LONG time
  reg[028h] = 0000h -- W_AID_LOW     ;\clear W_AID value, again?!
  reg[02Ah] = 0000h -- W_AID_FULL    ;/
  reg[0E8h] = 0001h -- W_US_COUNTCNT ;enable microsecond counter
  reg[038h] = 0000h -- W_POWER_TX    ;disable transmit power save
  reg[020h] = 0000h -- W_BSSID_0     ;\
  reg[022h] = 0000h -- W_BSSID_1     ; clear BSSID
  reg[024h] = 0000h -- W_BSSID_2     ;/
</PRE></TD></TR></TBODY></TABLE>-- TX prepare<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[0AEh] = 000Dh -- W_TXREQ_SET   ;flush all pending transmits (uh?)
</PRE></TD></TR></TBODY></TABLE>-- RX prepare<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[030h] = 8000h    W_RXCNT         ;enable RX system (done again below)
  reg[050h] = 4C00h    W_RXBUF_BEGIN   ;(example values)
  reg[052h] = 5F60h    W_RXBUF_END     ;(length = 4960 bytes)
  reg[056h] = 0C00h/2  W_RXBUF_WR_ADDR ;fifo begin latch address
  reg[05Ah] = 0C00h/2  W_RXBUF_READCSR     ;fifo end, same as begin at start.
  reg[062h] = 5F60h-2  W_RXBUF_GAP     ;(set gap&lt;end) (zero should work, too)
  reg[030h] = 8001h    W_RXCNT  ;enable, and latch new fifo values to hardware
</PRE></TD></TR></TBODY></TABLE>--<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  reg[030h] = 8000h    W_RXCNT       enable receive (again?)
  reg[010h] = FFFFh    W_IF          clear interrupt flags
  reg[012h] = whatever W_IE          set enabled interrupts
  reg[1AEh] = 1FFFh    W_RXSTAT_OVF_IE desired STAT Overflow interrupts
  reg[1AAh] = 0000h    W_RXSTAT_INC_IE desired STAT Increase interrupts
  reg[0D0h] = 0181h    W_RXFILTER set to 0x581 when you successfully connect
                        to an access point and fill W_BSSID with a mac
                        address for it. (W_RXFILTER) [not sure on the values
                        for this yet]
  reg[0E0h] = 000Bh  -- W_RXFILTER2     ;
  reg[008h] = 0000h  -- ? W_TXSTATCNT   ;(again?)
  reg[00Ah] = 0000h  -- ? W_X_00Ah      ;(related to rx filter) (again?)
  reg[004h] = 0001h  -- W_MODE_RST      ;hardware mode
  reg[0E8h] = 0001h  -- W_US_COUNTCNT   ;enable microsecond counter (again?)
  reg[0EAh] = 0001h  -- W_US_COMPARECNT ;enable microsecond compare
  reg[048h] = 0000h  -- W_POWER_?    ;[disabling a power saving technique]
  reg[038h].Bit1 = 0 -- W_POWER_TX   ;[this too]
  reg[048h] = 0000h  -- W_POWER_?    ;[umm, it's done again. necessary?]
  reg[0AEh] = 0002h  -- W_TXREQ_SET  ;
  reg[03Ch].Bit1 = 1 -- W_POWERSTATE ;queue enable power (RX power, we believe)
  reg[0ACh] = FFFFh  -- W_TXREQ_RESET;reset LOC1..3
</PRE></TD></TR></TBODY></TABLE>That's it, the DS should be now happy to send 
and receive packets.<BR>It's very possible that there are some unnecessary 
registers set in here.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswififlowcharts></A><FONT size=+2>&nbsp;DS Wifi 
      Flowcharts</FONT></TD></TR></TBODY></TABLE><BR><B>Wifi Transmit 
Procedure</B><BR>To transmit data via wifi (Assuming you've already initialized 
wifi and changed channels to the channel you want):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> (1) Copy the TX Header followed by the 802.11 packet to send anywhere it
      will fit in MAC memory (halfword-aligned)
 (2) Take the offset from start of MAC memory that you put the packet,
      divide it by 2, and or with 0x8000 - store this in one of the
      W_TXBUF_LOC registers
 (3) Set W_TX_RETRYLIMIT, to allow your packet to be retried until an ack is
      received (set it to 7, or something similar)
 (4) Store the bit associated with the W_TXBUF_LOC register you used
      into W_TXREQ_SET - this will send the packet.
 (5) You can then read the result data in W_TXSTAT when the TX is over
      (you can tell either by polling or interrupt) to find out how many
      retries were used, and if the packet was ACK'd
</PRE></TD></TR></TBODY></TABLE>Of course, this is just the simplest approach, 
you can be a lot more clever about it.<BR><BR><B>Wifi Receive 
Procedure</B><BR>To receive data via wifi, you either need to handle the wifi 
received data interrupt, or you need to poll W_RXBUF_WRCSR - whenever it is != 
W_RXBUF_READCSR, there is a new packet. When there is a new packet, take the 
following approach:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE> (1) Calculate the length of the new packet (read "received frame length"
      which is +8 bytes from the start of the packet) - total frame length
      is (12 + received frame length) padded to a multiple of 4 bytes.
 (2) Read the data out of the RX FIFO area (keep in mind it's a circular
      buffer and you may have to wrap around the end of the buffer)
 (3) Set the value of W_RXBUF_READCSR to the location of the next packet
      (add the length of the packet, and wrap around if necessary)
</PRE></TD></TR></TBODY></TABLE>Keep in mind, W_RXBUF_READCSR and W_RXBUF_WRCSR 
must be multiplied by 2 to get a byte offset from the start of MAC 
memory.<BR><BR><B>Wifi Change Channels Procedure (ch=1..14)</B><BR>For Type2 
(ie. firmware[040h]&lt;&gt;3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  RF[firmware[F2h+(ch-1)*6]/40000h] = firmware[F2h+(ch-1)*6] AND 3FFFFh
  RF[firmware[F5h+(ch-1)*6]/40000h] = firmware[F5h+(ch-1)*6] AND 3FFFFh
  delay a few milliseconds  ;huh?
  BB[1Eh] = firmware[146h+(ch-1)]
</PRE></TD></TR></TBODY></TABLE>For Type3 (ie. firmware[040h]=3):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  num_initial_regs = firmware[042h]
  addr=0CEh+num_initial_regs
  num_bb_writes = firmware[addr]
  num_rf_writes = firmware[43h]
  addr=addr+1
  for i=1 to num_bb_writes
    BB[firmware[addr]] = firmware[addr+ch]
    addr=addr+15
  next i
  for i=1 to num_rf_writes
    RF[firmware[addr]] = firmware[addr+ch]
    addr=addr+15
  next i
</PRE></TD></TR></TBODY></TABLE>Congrats, you are now ready to transmit/receive 
on whatever channel you picked.<BR><BR><B>Channels</B><BR>The IEEE802.11b 
standard (and the NDS hardware) support 14 channels (1..14).<BR>Channels 1..13 
use frequencies 2412MHz..2472MHz (in 5MHz steps). Channel 14 uses frequency 
2484MHz. Which channels are allowed to be used varies from country to country, 
as indicated by Bit1..14 of firmware[03Ch]. Channel 14 is rarely used (dated 
back to an older japanese standard).<BR><BR>Caution: Nearby channels do overlap, 
you'll get transmission errors on packets that are transferred simultaneously 
with packets on nearby channels. But, you won't successfully receive packets 
from nearby channels (so you won't even "see" that they are there, which is bad, 
as it doesn't allow you to share the channel synchronized with other hosts; ie. 
it'd be better if two hosts are using the SAME channel, rather than to use 
nearby channels).<BR>To avoid that problem, conventionally only channels 1,6,11 
are used - however Nintendo uses channels 1,7,13 - which is causing conflicts 
between channel 6,7, and maybe also between 11,13.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifihardwareheaders></A><FONT size=+2>&nbsp;DS Wifi Hardware 
      Headers</FONT></TD></TR></TBODY></TABLE><BR><B>Hardware TX Header (12 
bytes)</B><BR>The TX header immediately precedes the data to be sent, and should 
be put at the location that will be given to the register activating a 
transmission.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Siz Expl.
  00h  2   Status - In: Don't care - Out: Status (0000h=Failed, 0001h=Okay)
  02h  2   Unknown - In: Don't care
  04h  1   Unknown - In: Must be 00h..02h (should be 00h)
             (03h..FFh result in error: W_TXSTAT.Bit1 gets set, but
             nethertheless header entry[00h] is kept set to 0001h=Okay)
             ;00h = use W_TX_SEQNO (if enabled in TXBUF_LOCn)
             ;01h = force NOT to use W_TX_SEQNO (even if it is enabled in LOCn)
             ;02h = seems to behave same as 01h
  05h  1   Unknown - In: Don't care - Out: Set to 00h
  06h  2   Unknown - In: Don't care
  08h  1   Transfer Rate (0Ah=1Mbit/s, 14h=2Mbit/s) (other values=1MBit/s, too)
  09h  1   Unknown - In: Don't care
  0Ah  2   Length of IEEE Frame Header+Body+checksum(s) in bytes
           (14bits, upper 2bits are unused/don't care)
</PRE></TD></TR></TBODY></TABLE>The eight "Don't care" bytes should be usually 
set to zero (although setting them to FFh seems to be working as well). Entries 
[00h] and [05h] are modified by hardware, all other entries are kept 
unchanged.<BR><BR>Important note! TX length includes the length of a 4-byte 
"FCS" (checksum) for the packet. The hardware generates the FCS for you, but you 
still must include it in the packet length. Also note that if the 802.11 WEP 
enabled bit is set in the header, the packet will be automatically encrypted via 
the wep algorithm - however, the software is responsible for providing the 
4-byte IV block with the WEP key ID and the 24bit IV value. - ALSO, you must 
include the length of the *encrypted* FCS used in packets that have wep enabled 
(increase the tx length by another 4 bytes) - this value is calculated 
automaticly for you, but you are responsible for including it in the length of 
your packet (if you have data there, it'll be replaced by the 
FCS.)<BR><BR><B>Hardware RX Header (12 bytes)</B><BR>The RX header is an 
informational structure that provides needed information about a received 
packet. It is written right before the received packet data in the rx circular 
buffer.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Addr Siz Expl.
  00h  2   Flags
             Bit0-3: Frame type/subtype:
               0  managment/any frame (except beacon and invalid subtypes)
               1  managment/beacon frame
               5  control/ps-poll frame
               8  data/any frame (subtype0..7) (ie. except invalid subtypes)
               C,D,E,F  unknown (firmware is checking for that values)
             Bit4:   Seems to be always set
             Bit5-7: Seems to be always zero
             Bit8: Set when FC.Bit10 is set (more fragments)
             Bit9: Set when the lower-4bit of Sequence Control are nonzero,
                   it is also set when FC.Bit10 is set (more fragments)
                   So, probably, it is set on fragment-mismatch-errors
             Bit10-14: Seems to be always zero
             Bit15: Set when Frame Header's BSSID value equals W_BSSID register
  02h  2   Unknown (usually 0040h)
  04h  2   Time since last packet (eg. when receiving beacons: total random on
            first some packets, but later on it gets equal to Beacon Interval)
            In other cases, this value is equal to the 1st 2 bytes of the DA ?
            [Above time/da effects might be explained by other reason: maybe
            this entry is left unchanged, simply containing old WifiRAM value?]
  06h  2   Transfer Rate (N*100kbit/s) (ie. 14h for 2Mbit/s)
  08h  2   Length of IEEE Frame Header+Body in bytes (excluding FCS checksum)
  0Ah  1   MAX RSSI
  0Bh  1   MIN RSSI
</PRE></TD></TR></TBODY></TABLE>Important Note: Received frame lengths are 
always multiples of 4 bytes. While the actual header length + received frame 
length may be less, when incrementing the read cursor you must pad the length to 
a multiple of 4 bytes.<BR><BR><B>IEEE Header</B><BR>The above Hardware headers 
should (must) be followed by valid IEEE headers. Although that headers are to be 
generated by software, the hardware does do some interaction with the IEEE 
headers, such like comparing address fields with W_MACADDR and W_BSSID. And, it 
does modify some entries of it:<BR>1) The sequence control value is replaced by 
W_TX_SEQNO*10h (when enabled in W_TXBUF_LOCn.Bit13), this replacement does also 
overwrite the local TXBUF value.<BR>2) The frame control value is modified, 
namely, the hardware tends to set Bit12 of it. This replacement does NOT modify 
the local TXBUF, but the remote RXBUF will receive the modified value. Also, 
Bit0-1 (protocol version) are forcefully set to 0.<BR>3) Transmits via 
W_TXBUF_BEACON do additionally modify the 64bit timestamp (so W_TXBUF_BEACON 
should be used ONLY for packets WITH timestamp, ie. Beacons or Probe-Responses). 
The local TXBUF seems to be left unchanged, but the remote RXBUF will contain 
the (sender's) W_US_COUNT value.<BR>C) For Control Frames, the hardware headers 
Length value is transferred as normally (ie. excluding the FCS length, remote 
RXBUF will contain TXBUF length minus 4), but - no matter of that length value - 
only 10 or 16 bytes (depending on the subtype) of the IEEE frame are actually 
transferred and/or stored in RXBUF.<BR>X) For Control Frames with Subtype 0Ah, 
the AID entry is set to C000h, that, probably ORed with original value in 
WifiRAM, or with the W_AID_FULL register?<BR>XX) No idea if it's possible to 
send Control Frames with subtype 0Bh..0Fh, as for now, it seems that either they 
aren't sent, or the receipient is ignoring them (or processing them internally, 
but without storing them in RXBUF).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifimultiboot></A><FONT size=+2>&nbsp;DS Wifi 
      Multiboot</FONT></TD></TR></TBODY></TABLE><BR>Available Game 
Advertisement<BR>WMB uses beacon frames to advertise available games for 
download. The beacon frames are normally used to advertise available access 
points in most 802.11 systems, but there is nothing preventing their use in this 
capacity. The advertisement data is fragmented and stored partially in each 
beacon frame as the payload of a custom information element (tag: 
0xDD).<BR><BR>The DS Download Play menu only lists games when the beacons are 
broadcasted on one of the following channels: 1, 3, 4, 5, 7, 9, 10, 11, 13, and 
14 (that is WRONG, firmware_v3 checks only channels 1,7,13). However, the DS 
hosting mechanism only seems to transmit on channels 1, 7, and 13 (apparently 
selected at random).<BR><BR>All beacon frames transmitted by a DS host have the 
following format:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  802.11 management frame
  802.11 beacon header
  Supported rates (tagged IE, advertises 1 Mbit and 2 Mbit)
  DS parameter set (tagged IE, note: Distribution System, not Nintendo DS)
  TIM vector (tagged IE, transmitted as empty)
  Custom extension (tagged IE, tag 0xDD)
</PRE></TD></TR></TBODY></TABLE><BR>Nintendo specific beacon fragment format 
(information element code 0xDD):<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Offset Description
  00h  Nintendo Beacon ID (00h,09h,BFh,00h)
  04h  Stepping Offset for 4808134h/W_BEACONCOUNT2 (always 000Ah)
  06h  Strange Timestamp (W_US_COUNT*2-VCOUNT*7Fh)/128 (0000h for multiboot)
  08h  01 00
  0Ah  40 00
  0Ch  24 00
  0Eh  40 00
  10h  Randomly generated stream code
  12h  Number of bytes from entry 18h and up (70h for multiboot) (0 if Empty)
  13h  Beacon Type    (0Bh=Multiboot, 01h=Multicart/Pictochat, 09h=Empty)
  14h  0100 0008    (some kind of max,min values?)
</PRE></TD></TR></TBODY></TABLE>For Empty (length zero, is used at very begin of 
multiboot)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  18h  No data.
</PRE></TD></TR></TBODY></TABLE>For Multicart (variable length)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  18h  Custom data, usually containing the host name, either in 8bit ascii,
       or 16bit unicode format. Sometimes taken from Firmware User Settings,
       and sometimes from Cartridge Backup Memory.
</PRE></TD></TR></TBODY></TABLE>For Pictochat (length 8)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  18h  Fixed (always 2348h)
  1Ah  xxxx
  1Ch  Chatroom number (00h..03h for Chatroom A..D)
  1Dh  Number of users already connected (01h..10h) (including host)
  1Eh  Fixed (always 0004h)
</PRE></TD></TR></TBODY></TABLE>For Multiboot (always 70h bytes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  18h  24 00 40 00 (varies from game to game)
  1Ch  End of advertisement flag (00 for non-end, 02 for end packets)
  1Dh  Always 00, 01, 02, or 04
  1Eh  Number of players already connected
  1Fh  Sequence number (0 .. total_advertisement_length)
  20h  Checksum (on entries 22h and up)
         chksum=0, for i=22h to 86h step 2, chksum=chksum+halfword[i], next i,
         chksum=FFFFh AND NOT (chksum+chksum/10000h)
  22h  Sequence number in non-final packet, # of players in final packet
  23h  Total advertisement length - 1 (in beacons)
  24h  Datasize in bytes (2 byte little-endian)
           (0062h for seq 0..7, 0048h for seq 8, 0001h for seq 9)
  26h  Data (always 62h bytes, padded with 00h if Datasize&lt;62h)
</PRE></TD></TR></TBODY></TABLE><BR>The advertisement fragments are reordered 
and assembled according to their internal sequence number, to form the overall 
advertisement payload, as defined below:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Offset Size Description
  000h  32  Icon Palette (same as for ROM Cartridge Icon)
  020h  512 Icon Bitmap  (same as for ROM Cartridge Icon)
  220h  1   Unknown (0Bh)
  221h  1   Length of hosting name          ;(probably same as firmware
  222h  20  Name of hosting DS (10 UCS-2)   ;user name?)
  236h  1   Max number of players
  237h  1   Unknown (00h)
  238h  96  Game name (48 UCS-2)   (same as 1st line of ROM Cartridge Title)
  298h  192 Description (96 UCS-2) (same as further lines of ROM Cart Title)
  358h  64  00's if no users are connected  &lt;---WRONG: LEN=1, not 64
  398h  0   End of data if no users are connected
</PRE></TD></TR></TBODY></TABLE><BR><B>Authentication process</B><BR>Once a user 
B chooses a download offered by a host A, the following standard 802.11 
authentication process observed.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Host A advertises a game in beacon frames as described above
  Client B sends an authentication request (sequence 1) to A
  Host A replies with an ACK
  Host A sends an authentication reply (sequence 2) to B
  Client B replies with an association request
  Host A replies with an ACK
  Host A sends an association response
  Client B responds with an ACK
</PRE></TD></TR></TBODY></TABLE>After this, the two are associated, and will 
remain so until the transfer is complete or one is idle for several seconds, at 
which point they will de-associate. For more information on the association 
process, see the 802.11 standard.<BR><BR><B>Download process (after 
authentication)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Host sends Pings (type 0x01, replies are 0x00, 0x07)
  Host sends RSA frame (type 0x03, replies 0x08)
  Host sends NDS header (type 0x04, replies 0x09)
  Host sends ARM9 binary (type 0x04, replies 0x09)
  Host sends ARM7 binary (type 0x04, replies 0x09)
  Host terminates transfer (type 0x05, no replies)
</PRE></TD></TR></TBODY></TABLE><BR>The WMB protocol ostensibly implements 
layers 3 to 7 of the OSI network model, but does not define a new type of 
network addresses. However, it does define a couple of special broadcast-like 
MAC addresses within the assigned Nintendo namespace (00:09:BF).<BR><BR>The 
three channels or flows used for all communications after the MAC broadcast 
beacons take the form 03:09:BF:00:00:xx, where xx is:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00 for the main data flow, from host to client    (sent via Port 090h)
  10 for the client to host replies                 (sent via Port 094h)
  03 for the feedback flow, host to client (acknowledges the replies)
</PRE></TD></TR></TBODY></TABLE><BR>Observed commands:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Command   Description
  0x01      Ping / Name request
  0x03      RSA signature frame
  0x04      Data packet
  0x05      Post-idle / unknown
</PRE></TD></TR></TBODY></TABLE><BR>Observed replies<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Reply ID  Description
  0x00      Pong (ping reply)
  0x07      Name reply
  0x08      RSA frame reply
  0x09      Data packet reply
</PRE></TD></TR></TBODY></TABLE><BR>The host does something unusual with the 
802.11 sequence control field, each packet sent out on the 00 flow has a 
sequence control number 2 greater than the previous one, even if they are sent 
sequentially. When the host acknowledges a reply (on flow 03) from the client 
about a particular packet, it uses the sequence number one after the original 
packet number it sent out on 00. This is the root of one of the major problems 
in finding a PC card that can transmit WMB packets, as very few cards provide 
user control over it. Even when a card is capable of `raw' 802.11 transmission, 
it typically takes care of the sequence control field in hardware or firmware, 
filling it with a constantly incrementing number.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  -------------------
</PRE></TD></TR></TBODY></TABLE><BR>Host-to-client packets (on the 0x00 
flow)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2  3  4    5     6..e-3   e-2  e-1  e-0
  06 01 02 00 Size Flags Payload  00   02   00
</PRE></TD></TR></TBODY></TABLE>The size field is in terms of half-words (16 
bits), and includes the flags byte along with the payload (so a size of 0x03 
represents a flag byte, a command byte, and 4 bytes of payload).<BR>When flags 
is 0x11, the first byte of the payload is a command. There seems to be no 
important data when flags is not 0x11 (seen occasionally as 0x01), and ignoring 
them still results in a complete dump.<BR><BR>The Ping messages (type 0x00) have 
a payload size of 0x03, but always contain zeroes in the payload. They seem to 
be used only to keep the connection alive while waiting for the host DS to start 
the transfer, to prevent a time-out de-association.<BR><BR><B>RSA signature 
frame payload (type 0x03)</B><BR>The RSA frame format (type 0x03) sends a table 
of information about the game being downloaded (most of it redundant with the 
NDS header, see Appendix), as well as the RSA signature for the DS. I have not 
looked into computing the signature, as homebrew developers are not privy to 
Nintendo's private key, making signing a fruitless activity, but it is my 
understanding that the signature is a 128 byte public key and an 8 byte SHA-1 
message digest over the NDS header, ARM9 binary, and ARM7 binary. Notably: the 
RSA frame itself is not included as part of the data being signed, bringing up 
various security issues and making Nintendo's firmware engineers look amateurish 
at best.<BR>There are several abortive sendings of empty RSA frames with a size 
field of 0x03, before the real frame is sent (always with a size field of 
0x75).<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Offset Size Description
  0x00 4   ARM9 execute address
  0x04 4   ARM7 execute address
  0x08 4   0x00
  0x0C 4   Header destination
  0x10 4   Header destination
  0x14 4   Header size (0x160)
  0x18 4   0x00
  0x1C 4   ARM9 destination address
  0x20 4   ARM9 destination address
  0x24 4   ARM9 binary size
  0x28 4   0x00
  0x2C 4   0x022C0000
  0x30 4   ARM7 destination address
  0x34 4   ARM7 binary size
  0x38 4   0x01
  0x3C 136 Signature block
  0xC4 36  0x00's
  0xE8 0   End of frame payload
</PRE></TD></TR></TBODY></TABLE>The offsets in the table are from after the 
command byte, i.e. two bytes into the 234 bytes of payload including the 
flags.<BR>The unknown address 0x022C0000 is probably ARM7 related, by comparison 
with the duplicated header and ARM9 destination addresses 32 and 16 bytes before 
it, although it has no known significance according to the NDS 
header.<BR><BR><B>Data packet (type 0x04)</B><BR>The data packets (type 0x04) 
include a transport-layer sequence number inside of the data packet itself, but 
no destination offset or other mechanism to allow the packets to be processed 
out-of-order. The only way to place the data at the correct location in memory 
is to re-order the packets according to the sequence number and process them 
sequentially.<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1     2       3   ..  End
  00 [Sequence #]  xx  ..  yy
</PRE></TD></TR></TBODY></TABLE>The sequence number is a zero based 
little-endian number. Each packet only contains data for one of the three 
destination blocks (header, ARM9, ARM7), so the change-of-destination check only 
needs to be made on packet boundaries.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  -------------------
</PRE></TD></TR></TBODY></TABLE><BR>Client to Host Replies (on the 0x10 
flow)<BR>The replies from client to host are sent on the 0x10 flow. The client 
uses an incrementing sequence control number for all of its packets, with no 
unusual trickery. Each reply is sent as a standard 802.11 data frame (typically 
as a Data + CF-Acknowledgement), consisting of 10 data bytes for the WMB 
payload. The first two are always 0x04 0x81, with the third byte indicating the 
type of reply, and the remaining 7 bytes being 
reply-specific.<BR><BR><BR><B>Idle / Pong reply (type 0x00)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2  3  4  5  6  7  8  9
  04 81 00 00 00 00 00 00 00 00
</PRE></TD></TR></TBODY></TABLE>One type of packet frequently sent before a 
download gets underway is what I have termed the Idle or Pong packet (in 
response to 0x00 `Pings'). It has a reply type field of 0x00, and does not 
contribute any additional information.<BR><BR><B>Name reply (type 0x07)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2  3  4     5      6     7      8     9
  04 81 07 01 [Character0] [Character1] [Character2]
  04 81 07 02 [Character3] [Character4] [Character5]
  04 81 07 03 [Character6] [Character7] [Character8]
  04 81 07 04 [Character9] 01    00     00    00
</PRE></TD></TR></TBODY></TABLE>The name reply (type 0x07) is sent shortly after 
association is completed, although I am not certain what triggers it. There are 
a variable number of pings preceding this reply, but most are replied via Pongs. 
The name reply sends the user-configured DS name (set in the firmware menu) 
split over four messages (with the 4th byte of the packet specifying which 
message fragment this is, 1 based). This can be a total length of 10 UCS-2 
characters, although all four messages are still sent if it is shorter (padded 
with nulls to 10 characters, and then 01 and then nulls until the end of the 
frame).<BR><BR><B>RSA frame receipt reply (type 0x08)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2  3  4  5  6  7  8  9
  04 81 08 xx xx xx xx xx xx xx
</PRE></TD></TR></TBODY></TABLE>The RSA frame receipt reply contains no extra 
information; it only acknowledges receipt of a type 0x03 host packet on the main 
flow (0x00). Bizarrely, the xx bytes in the above table are not driven to a 
particular value when replying to an RSA frame, and usually contain the same 
data as the second (of four) name response frames.<BR><BR><B>Data packet receipt 
reply (type 0x09)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2    3    4        5     6     7  8  9
  04 81 09 [Last packet] [Best packet] 00 00 00
</PRE></TD></TR></TBODY></TABLE>[last packet] is the packet number being 
acknowledged<BR>[best packet] is the highest continuous packet number seen so 
far<BR>Packet IDs are little-endian numbers, like other Nintendo provided 
data.<BR><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  -------------------
</PRE></TD></TR></TBODY></TABLE><BR>Host to client acknowledgements (on the 0x03 
flow)<BR><BR>These packets contain four data bytes, but three are always zero. 
The first seems to be random, with no connection to the acknowledged data. The 
actual indication of acknowledgement is the sequence control number of the 
packet. It is set to be one greater than the sequence control number of the 
initial host packet (sent on flow 0x00) that the client has just responded to, 
to indicate that the reply was received.<BR><BR><B>Host-to-client 
acknowledgement</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0  1  2  3
  ?? 00 00 00
</PRE></TD></TR></TBODY></TABLE><BR>The .NDS format is the standard format for 
Nintendo DS programs; it originated on original game cards and also appears to a 
limited extent in WMB binaries. The WMB process only transfers the first 0x160 
bytes of the header, the ARM9 binary, and the ARM7 binary (in that order), 
ignoring the file name and file allocation tables, the overlay data, and some 
information stored in the banner (the rest is transmitted partially via the 
beacon advertisement process).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiieee80211frames></A><FONT size=+2>&nbsp;DS Wifi 
      IEEE802.11 Frames</FONT></TD></TR></TBODY></TABLE><BR><B>MAC Frame 
Format</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  10..30 bytes    MAC Header
  0..2312 bytes   Frame Body
  4 bytes         Frame Check Sequence (FCS) (aka checksum)
</PRE></TD></TR></TBODY></TABLE><BR><B>MAC Header (10..30 bytes)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Size Content
  2    Frame Control Field (FC)
  2    Duration/ID
  6    Address 1
 (6)   Address 2 (if any)
 (6)   Address 3 (if any)
 (2)   Sequence Control (if any)
 (6)   Address 4 (if any)
</PRE></TD></TR></TBODY></TABLE><BR><B>Frame Control Field (FC)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Expl.
  0-1  Protocol Version   (0=Current, 1..3=Reserved)
  2-3  Type               (0=Managment, 1=Control, 2=Data, 3=Reserved)
  4-7  Subtype            (see next chapters) (meaning depends on above Type)
  8    To Distribution System (DS)
  9    From Distribution System (DS)
  10   More Fragments
  11   Retry
  12   Power Managment    (0=Active, 1=STA will enter Power-Safe mode after..)
  13   More Data
  14   Wired Equivalent Privacy (WEP)
  15   Order
</PRE></TD></TR></TBODY></TABLE>Bit 8-11 and Bit 13-15 are always 0 in Control 
Frames.<BR><BR><B>Duration/ID Field (16bit)</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0000h..7FFFh  Duration (0-32767)
  8000h         Fixed value within frames transmitted during the CFP
                (CFP=Contention Free Period)
  8001h..BFFFh  Reserved
  C000h         Reserved
  C001h..C7D7h  Association ID (AID) (1..2007) in PS-Poll frames
  C7D8h..FFFFh  Reserved
</PRE></TD></TR></TBODY></TABLE><BR><B>48bit MAC Addresses</B><BR>MAC Addresses 
are 48bit (6 bytes) (Bit0 is the LSB of the 1st byte),<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0     Group Flag (0=Individual Address, 1=Group Address)
  1     Local Flag (0=Universally Administered Address, 1=Locally Administered)
  2-23  22bit Manufacturer ID (assigned by IEEE)
  24-47 24bit Device ID (assigned by the Manufacturer)
</PRE></TD></TR></TBODY></TABLE>Special NDS related Addresses:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00 09 BF xx xx xx  NDS-Consoles (Original NDS with firmware v1-v5)
  00 16 56 xx xx xx  NDS-Consoles (Newer NDS-Lite with firmware v6 and up)
  03 09 BF 00 00 00  NDS-Multiboot: host to client (main data flow)
  03 09 BF 00 00 10  NDS-Multiboot: client to host (replies)
  03 09 BF 00 00 03  NDS-Multiboot: host to client (acknowledges replies)
  FF FF FF FF FF FF  Broadcast to all stations (eg. Beacons)
</PRE></TD></TR></TBODY></TABLE><BR><B>Sequence Control Field</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit  Expl.
  0-3  Fragment Number (0=First (or only) fragment)
  4-15 Sequence Number
</PRE></TD></TR></TBODY></TABLE>(increment by 1, except on retransmissions, ie. 
retries)<BR><BR><B>WEP Frame Body</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  3 bytes     Initialization Vector
  1 byte      Pad (6bit, all zero), Key ID (2bit)
  1..? bytes  Data (encrypted data)
  4 bytes     ICV (encrypted CRC32 across Data)
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiieee80211managmentframestype0></A><FONT size=+2>&nbsp;DS 
      Wifi IEEE802.11 Managment Frames 
(Type=0)</FONT></TD></TR></TBODY></TABLE><BR>All Managment Frames have 24-byte 
Frame Header, with following values:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  FC(2), Duration(2), DA(6), SA(6), BSSID(6), Sequence Control(2)
</PRE></TD></TR></TBODY></TABLE>The content of the Frame Body depends on the 
FC's Subtype:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Subtype                   Frame Body
  0 Association request     Capability, ListenInterval, SSID, SuppRates
  1 Association response    Capability, Status, AID, SuppRates
  2 Reassociation request   Capability, ListenInterval, CurrAP, SSID, SuppRates
  3 Reassociation response  Capability, Status, AID, SuppRates
  4 Probe request           SSID, SuppRates
  5 Probe response          Same as for Beacon (but without TIM)
  8 Beacon                  Timestamp,BeaconInterval,Capability,SSID,SuppRates,
                             FH Parameter Set (when using Frequency Hopping),
                             DS Parameter Set (when using Direct Sequence),
                             CF Parameter Set (when supporting PCF),
                             IBSS Parameter Set (when in an IBSS),
                             TIM (when generated by AP)
  9 Announcement traffic indication message (ATIM)    Body is "null" (=none?)
  A Disassociation          ReasonCode
  B Authentication          AuthAlgorithm, AuthSequence, Status, ChallengeText
  C Deauthentication        ReasonCode
</PRE></TD></TR></TBODY></TABLE>Subtypes 6..7, and D..F are 
Reserved.<BR><BR><B>The separate components of the Frame Body 
are...</B><BR>64bit Parameters (8 bytes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Timestamp: value of the TSFTIMER (see 11.1) of a frame's source. Uh?
</PRE></TD></TR></TBODY></TABLE>48bit Parameters (6 bytes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Current AP (Access Point): MAC Address of AP with which station is associated
</PRE></TD></TR></TBODY></TABLE>16bit Parameters (2 bytes)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Capability Information (see list below)
  Status code (see list below) (0000h=Successful, other=Error code)
  Reason code (see list below) (Error code)
  Association ID (AID) (C000h+1..2007)
  Authentication Algorithm (0=Open System, 1=Shared Key, 2..FFFFh=Reserved)
  Authentication Transaction Sequence Number (Open System:1-2, Shared Key:1-4)
  Beacon Interval (Time between beacons, N*1024 us)
  Listen Interval (see note below)
</PRE></TD></TR></TBODY></TABLE>Information elements (1byte ID, 1byte LEN, 
followed by LEN byte(s) data)<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ID      LEN      Expl.
  00h     00h-20h  SSID (LEN=0 for broadcast SSID)
  01h     01h-08h  Supported rates; each (nn AND 7Fh)*500kbit/s, bit7=flag
  02h     05h      FH (Frequency Hopping) Parameter Set
                     DwellTime(16bit), HopSet, HopPattern, HopIndex
  03h     01h      DS (Distribution System) Parameter Set; Channel (01h..0Eh)
  04h     06h      CF Parameter Set; Count, Period, MaxDuration, RemainDuration
  05h     04h..FEh TIM; Count,Period,Control, 1-251 bytes PartialVirtualBitmap
  06h     02h      IBSS Parameter Set; ATIM Window length (16bit)
  07h-0Fh -        Reserved
  10h     02h..FEh Challenge text; 1-253 bytes Authentication data
                    (Used only for Shared Key sequence no 2,3)
                    (none such for Open System)
                    (none such for Shared key sequence no 1,4)
  11h-1Fh -        Reserved for challenge text extension
  20h-FFh -        Reserved
  DDh     var      Reserved but used by Nintendo for NDS-Multiboot beacons
</PRE></TD></TR></TBODY></TABLE>IDs 20h-FFh are commonly used; I've received 
values 2xh..3xh and DDh (from non-nintendo network routers in the neighborhood); 
no idea if these "Reserved" IDs are somewhere officially 
documented?<BR><BR><B>Capability Information</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Bit0    ESS
  Bit1    IBSS
  Bit2    CF-Pollable
  Bit3    CF-Poll Request
  Bit4    Privacy
  Bit5    Short Preamble  (IEEE802.11b only)
  Bit6    PBCC            (IEEE802.11b only)
  Bit7    Channel Agility (IEEE802.11b only)
  Bit5-7  Reserved (0) (original IEEE802.11 specs)
  Bit8-15 Reserved (0)
</PRE></TD></TR></TBODY></TABLE><BR><B>Listen Interval</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  ... used to indicate to the AP how often an STA wakes to listen to Beacon
  management frames. The value of this parameter is the STA's Listen Interval
  parameter of the MLME-Associate. request primitive and is expressed in
  units of Beacon Interval.
</PRE></TD></TR></TBODY></TABLE><BR><B>Reason codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h Reserved
  01h Unspecified reason
  02h Previous authentication no longer valid
  03h Deauthenticated because sending station is leaving (or has left) IBSS
       or ESS
  04h Disassociated due to inactivity
  05h Disassociated because AP is unable to handle all currently associated
       stations
  06h Class 2 frame received from nonauthenticated station
  07h Class 3 frame received from nonassociated station
  08h Disassociated because sending station is leaving (or has left) BSS
  09h Station requesting (re)association is not authenticated with responding
       station
  0Ah..FFFFh Reserved
</PRE></TD></TR></TBODY></TABLE><BR><B>Status codes</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  00h Successful
  01h Unspecified failure
  02h..09h Reserved
  0Ah Cannot support all requested cap's in the Capability Information field
  0Bh Reassociation denied due to inability to confirm that association exists
  0Ch Association denied due to reason outside the scope of this standard
  0Dh Responding station doesn't support the specified authentication algorithm
  0Eh Received an Authentication frame with authentication transaction sequence
       number out of expected sequence
  0Fh Authentication rejected because of challenge failure
  10h Authentication rejected due to timeout waiting for next frame in sequence
  11h Association denied because AP is unable to handle additional associated
       stations
  12h Association denied due to requesting station not supporting all of the
       data rates in the BSSBasicRateSet parameter
  13h Association denied due to requesting station not supporting
       the Short Preamble option (IEEE802.11b only)
  14h Association denied due to requesting station not supporting
       the PBCC Modulation option (IEEE802.11b only)
  15h Association denied due to requesting station not supporting
       the Channel Agility option (IEEE802.11b only)
  13h-15h Reserved (original IEEE802.11 specs)
  16h..FFFFh Reserved
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dswifiieee80211controlanddataframestype1and2></A><FONT 
      size=+2>&nbsp;DS Wifi IEEE802.11 Control and Data Frames (Type=1 and 
      2)</FONT></TD></TR></TBODY></TABLE><BR><B>Control Frames (Type=1)</B><BR>All 
Control Frames have 10-byte or 16-byte headers, depending on the Subtype:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Subtype                          Frame Header
  A   Power Save (PS)-Poll         FC  AID       BSSID  TA
  B   Request To Send (RTS)        FC  Duration  RA     TA
  C   Clear To Send (CTS)          FC  Duration  RA     -
  D   Acknowledgment (ACK)         FC  Duration  RA     -
  E   Contention-Free (CF)-End     FC  Duration  RA     BSSID
  F   CF-End + CF-Ack              FC  Duration  RA     BSSID
</PRE></TD></TR></TBODY></TABLE>Subtypes 0..9 are Reserved. Control Frames do 
not have a Frame Body, so the Header is directly followed by the 
FCS.<BR><BR><B>Data Frames (Type=2)</B><BR>All Data Frames consist of the 
following components:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  FC, Duration/ID, Address 1, Address 2, Address 3, Sequence Control,
  Address 4 (only on From DS to DS), Frame Body, FCS.
</PRE></TD></TR></TBODY></TABLE>The meaning of the 3 or 4 addresses depends on 
Frame Control FromDS/ToDS bits:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Frame Control    Address 1  Address 2  Address 3  Address 4
  From STA to STA  DA         SA         BSSID      -
  From DS  to STA  DA         BSSID      SA         -
  From STA to DS   BSSID      SA         DA         -
  From DS  to DS   RA         TA         DA         SA
</PRE></TD></TR></TBODY></TABLE>Frame Control Subtypes for Data Frames (Type=2) 
are:<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  0   Data
  1   Data + CF-Ack
  2   Data + CF-Poll
  3   Data + CF-Ack + CF-Poll
  4   Null function (no data)
  5   CF-Ack (no data)
  6   CF-Poll (no data)
  7   CF-Ack + CF-Poll (no data)
  8-F Reserved
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsbackwardscompatiblegbamode></A><FONT size=+2>&nbsp;DS 
      Backwards-compatible GBA-Mode</FONT></TD></TR></TBODY></TABLE><BR>When booting a 
32pin GBA cartridge, the NDS is automatically switched into GBA mode, in that 
mode all NDS related features are disabled, and the console behaves (almost) 
like a GBA.<BR><BR><B>GBA Features that are NOT supported on NDS in GBA 
Mode.</B><BR>Unlike real GBA, the NDS does not support 8bit DMG/CGB 
cartridges.<BR>The undocumented Internal Memory Control register (Port 800h) 
isn't supported, so the NDS doesn't allow to use 'overclocked' RAM.<BR>The NDS 
doesn't have a link-port, so GBA games can be played only in single player mode, 
link-port accessories cannot be used, and the NDS cannot run GBA code via 
multiboot.<BR><BR><B>GBA Features that are slightly different on NDS in GBA 
Mode.</B><BR>The CPU, Timers, and Sound Frequencies are probably clocked at 
16.76MHz; 33.51Mhz/2; a bit slower than the original GBA's 16.78MHz clock?<BR>In 
the BIOS, a single byte in a formerly 00h-filled area has been changed from 00h 
to 01h, resulting in SWI 0Dh returning a different BIOS checksum.<BR>The GBA 
picture can be shown on upper or lower screen (selectable in boot-menu), the 
backlight for the selected screen is always on, resulting in different colors 
&amp; much better visibility than original GBA. Unlike GBA-SP, the NDS doesn't 
have a backlight-button.<BR><BR><B>Screen Border in GBA mode</B><BR>The GBA 
screen is centered in the middle of the NDS screen. The surrounding pixels are 
defined by 32K-color bitmap data in VRAM Block A and B. Each frame, the GBA 
picture is captured into one block, and is displayed in the next frame (while 
capturing new data to the other block).<BR>To get a flicker-free border, both 
blocks should be initialized to contain the same image before entering GBA mode 
(usually both are zero-filled, resulting in a plain black border).<BR>Note: When 
using two different borders, the flickering will be irregular - so there appears 
to be a frame inserted or skipped once every some seconds in GBA 
mode?!<BR><BR><B>Switching from NDS Mode to GBA Mode</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  --- NDS9: ---
  ZEROFILL VRAM A,B     ;init black screen border (or other color/image)
  POWCNT=8003h          ;enable 2D engine A on upper screen (0003h=lower)
  EXMEMCNT=...          ;set Async Main Memory mode (clear bit14)
  IME=0                 ;disable interrupts
  SWI 06h               ;halt with interrupts disabled (lockdown)
  --- NDS7: ---
  POWERMAN.REG0=09h     ;enable sound amplifier &amp; upper backlight (05h=lower)
  IME=0                 ;disable interrupts
  wait for VCOUNT=200   ;wait until VBlank
  SWI 1Fh with R2=40h   ;enter GBA mode, by CustomHalt(40h)
</PRE></TD></TR></TBODY></TABLE>After that, the GBA BIOS will be booted, the GBA 
Intro will be displayed, and the GBA cartridge (if any) will be 
started.<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=dsxboo></A><FONT size=+2>&nbsp;DS 
Xboo</FONT></TD></TR></TBODY></TABLE><BR><B>DS XBOO Connection</B><BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  Console Pin/Names             Parallel Port Pin/Names
  RFU.9    FMW.1 D    ---|&gt;|--- DSUB.14    CNTR.14    AutoLF
  RFU.6    FMW.2 C    ---|&gt;|--- DSUB.1     CNTR.1     Strobe
  RFU.10   FMW.3 /RES ---|&gt;|--- DSUB.16    CNTR.31    Init
  RFU.7    FMW.4 /S   ---|&gt;|--- DSUB.17    CNTR.36    Select
  RFU.5    FMW.5 /W   --. SL1A  -          -          N.C.
  RFU.28   FMW.6 VCC  __| SL1B  -          -          N.C.
  RFU.2,12 FMW.7 VSS  --------- DSUB.18-25 CNTR.19-30 Ground
  RFU.8    FMW.8 Q    --------- DSUB.11    CNTR.11    Busy
  P00 Joypad-A        ---|&gt;|--- DSUB.2     CNTR.2     D0
  P01 Joypad-B        ---|&gt;|--- DSUB.3     CNTR.3     D1
  P02 Joypad-Select   ---|&gt;|--- DSUB.4     CNTR.4     D2
  P03 Joypad-Start    ---|&gt;|--- DSUB.5     CNTR.5     D3
  P04 Joypad-Right    ---|&gt;|--- DSUB.6     CNTR.6     D4
  P05 Joypad-Left     ---|&gt;|--- DSUB.7     CNTR.7     D5
  P06 Joypad-Up       ---|&gt;|--- DSUB.8     CNTR.8     D6
  P07 Joypad-Down     ---|&gt;|--- DSUB.9     CNTR.9     D7
  RTC.1 INT aka SI    --------- DSUB.10    CNTR.10    /Ack
</PRE></TD></TR></TBODY></TABLE>Parts List: 15 wires, four (DS) or twelve 
(DS-Lite) "BAT 85" diodes, 1 parallel port socket.<BR><BR><B>DS XBOO Connection 
Notes</B><BR>The Firmware chip (FMW.Pins) hides underneath of the RFU shielding 
plate, so it'd be easier to connect the wires to the RFU.Pins (except DS-Lite: 
The RFU pins are terribly small (and have different pin-numbers), so either 
using FMW.Pins, or using mainboard vias (see below GIF) would be easier). The 
easiest way for the /W-to-VCC connection is to shortcut SL1 by putting some 
solder onto it.<BR>The P00..P07 and INT signals are labeled on the switch-side 
of the mainboard, however, there should be more room for the cables when 
connecting them to via's at the bottom-side (except DS-Lite: P01 is found only 
at switch-side) image below may help to locate that pins,<BR>
<TABLE border=0 cellSpacing=0 cellPadding=0>
  <TBODY>
  <TR>
    <TD><PRE>  http://nocash.emubase.de/nds-pins.gif (GIF-Image, 7.5KBytes)
</PRE></TD></TR></TBODY></TABLE>At the parallel port side, DSUB.Pins or 
CNTR.Pins can be used for 25pin DSUB or 36pin Centronics sockets, the latter one 
allowing to use a standard printer cable.<BR>The ring printed on the diodes is 
pointing towards parallel port side, the 4 diodes are required to prevent the 
parallel port to pull-up LOW levels on the NDS side, be sure to use BAT85 
diodes, cheaper ones like 1N4148 are loosing too much voltage and won't gain 
stable LOW levels.<BR>The power managment chip in the DS-Lite simply refuses to 
react to the Power-On button when P00..P07 are dragged high by the parallel port 
(even if it is in HighZ state), the 8 diodes in the data-lines are solving that 
problem (they are required on DS-Lite only, not on original DS).<BR><BR><B>DS 
XBOO Operation Notes</B><BR>The main Upload function is found in no$gba Utility 
menu, together with further functions in Remote Access sub-menu.<BR>Before 
uploading anything: download the original firmware, the file is saved as 
FIRMnnnn.BIN, whereas "nnnn" is equal to the last 16bit of the consoles 48bit 
MAC address, so Firmware-images from different consoles are having unique 
filenames. If you don't already have, also download the NDS BIOS, the BIOS 
contains encryption seed data required to encrypt/decrypt secure area; without 
having downloaded the BIOS, no$gba will be working only with unencrypted 
ROM-images. Next, select Patch Firmware to install the nocash 
firmware.<BR><BR><B>DS XBOO Troubleshooting</B><BR>Be sure that the console is 
switched on, and that the XBOO cable is connected, and that you have selected 
the correct parallel port in no$gba setup (the "multiboot" options in Various 
Options screen), and, of course, try avoid to be fiddling with the joypad during 
uploads.<BR>I've tested the cable on two computers, the overall upload/download 
stuff should work stable. The firmware access functions - which are required 
only for (un-)installation - worked only with one of the two computers; try 
using a different computer/parallel port in case of problems.<BR><BR><B>Nocash 
Firmware</B><BR>The primary purpose is to receive uploaded NDS-images via 
parallel port connection, additionally it's containing bootmenu and setup 
screens similar to the original firmware. The user interface is having less 
cryptic symbols and should be alltogether faster and easier to use. Important 
Information about Whatever is supported (but it can be disabled). The setup 
contains a couple of additional options like automatic daylight saving time 
adjustment.<BR>The bootmenu allows to boot normal NDS and GBA carts, it does 
additionally allow to boot NDS-images (or older PassMe-images) from flashcards 
in GBA slot. Furthermore, benefits of asm coding, the nocash firmware occupies 
less than 32KBytes, allowing to store (and boot) smaller NDS-images in the 
unused portion of the firmware memory (about 224KBytes), the zero-filled region 
between cart header and secure area, at 200h..3FFFh, is automatically excluded, 
so the image may be slightly bigger than the available free memory 
space.<BR><BR><B>Missing</B><BR>Unlike the original firmware, the current 
version cannot boot via WLAN. Help or hardware would be welcome (I am having 
only one NDS, and my PC doesn't have WLAN, so I cannot test any WLAN transfers 
right now).<BR><BR><BR>
<TABLE width="100%">
  <TBODY>
  <TR bgColor=#cccccc>
    <TD><A name=aboutthisdocument></A><FONT size=+2>&nbsp;About this 
      Document</FONT></TD></TR></TBODY></TABLE><BR><B>About</B><BR>GBATEK written 
2001-2007 by Martin Korth, programming specs for the GBA and NDS hardware, I've 
been trying to keep the specs both as short as possible, and as complete as 
possible. The document is part of the no$gba debuggers built-in help 
text.<BR><BR><B>Updates</B><BR>The standalone docs in TXT and HTM format are 
updated when having added any major changes to the document. The no$gba built-in 
version will be updated more regularly, including for minor changes, along with 
all no$gba updates.<BR><BR><B>Homepage</B><BR>http://nocash.emubase.de/gba.htm - 
no$gba emulator homepage (freeware)<BR>http://nocash.emubase.de/gba-dev.htm - 
no$gba debugger homepage<BR>http://nocash.emubase.de/gbapics.htm - no$gba 
debugger screenshots<BR>http://nocash.emubase.de/gbatek.htm - gbatek html 
version<BR>http://nocash.emubase.de/gbatek.txt - gbatek text 
version<BR><BR><B>Feedback</B><BR>If you find any information in this document 
to be misleading, incomplete, or incorrect, please say something! My 
spam-shielded email address is found at:<BR>http://nocash.emubase.de/email.htm - 
contact<BR>Mail from programmers only, please. No gaming questions, 
thanks.<BR><BR><B>Credits</B><BR>Thanks for GBATEK fixes, and for info about GBA 
and NDS hardware,<BR>- Jasper Vijn<BR>- Remi Veilleux (DS video details)<BR>- 
Randy Linden<BR>- Sebastian Rasmussen<BR>- Stephen Stair (DS Wifi)<BR>- Damien 
Good (DS Bios Dumping, and lots of e-Reader info)<BR>- Kenobi and Dualscreenman 
(lots of ARDS/CBDS cheat info)<BR>- Flubba (GBA X/Y-Axis tilt sensor, and GBA 
Gameboy Player info)<BR>- DarkFader (DS Key2)<BR>- Dstek.xml (DS Sound)<BR>- 
Christian Auby<BR>- Jeff Frohwein<BR>- NDSTech Wiki, 
http://www.bottledlight.com/ds/ (lots of DS 
info)<BR><BR><B>Formatting</B><BR>TXT is 80 columns, TXT is 80 columns, TXT is 
80 columns.<BR>Don't trust anything else. Never.<BR><BR><BR></P></BODY></HTML>
